web-dev-qa-db-fra.com

Quelle est la différence entre l'écriture de cas de test pour BDD et TDD?

J'ai appris à écrire des cas de test pour BDD (Behaviour Driven Development) en utilisant specflow. Si j'écris des tests complets avec BDD, est-il nécessaire d'écrire le test TDD (Test Driven Development) séparément? Est-il nécessaire d'écrire des cas de test pour TDD et BDD séparément, ou s'agit-il effectivement de la même chose?

Il me semble que les deux sont identiques, la seule différence étant que les cas de test BDD peuvent être compris par des non développeurs et testeurs.

247
arjun

La différence entre BDD et TDD est que BDD commence par un B et TDD commence par un T. Mais sérieusement, le piège avec TDD est que trop de développeurs se sont concentrés sur le "comment" lors de l'écriture de leurs tests unitaires, donc ils se sont retrouvés avec très des tests fragiles qui n'ont fait que confirmer que le système fait ce qu'il fait.

BDD fournit un nouveau vocabulaire et donc se concentre sur l'écriture d'un test unitaire. Fondamentalement, il s'agit d'une approche axée sur les fonctionnalités de TDD.

214
Michael Brown

Behavior Driven Development est une extension/révision de Test Driven Development. Son but est d'aider les gens qui conçoivent le système (c'est-à-dire les développeurs) à identifier les tests appropriés à écrire - c'est-à-dire des tests qui reflètent le comportement souhaité par les parties prenantes. L'effet finit par être le même - développer le test puis développer le code/système qui réussit le test. Le BDD espère que les tests sont réellement utiles pour montrer que le système répond aux exigences.

MISE À JOUR

Les unités de code (méthodes individuelles) peuvent être trop granulaires pour représenter le comportement représenté par les tests de comportement, mais vous devez toujours les tester avec des tests unitaires pour garantir leur bon fonctionnement. Si c'est ce que vous entendez par tests "TDD", alors oui, vous en avez toujours besoin.

51
Matthew Flynn

BDD utilise ce que l'on appelle un "langage omniprésent", un ensemble de connaissances qui peuvent être comprises par le développeur et le client. Ce langage omniprésent est utilisé pour façonner et développer les exigences et les tests nécessaires, au niveau de la compréhension du client.

Dans les limites des exigences et des tests dictés par BDD, vous utiliserez TDD "ordinaire" pour développer le logiciel. Les tests unitaires ainsi créés serviront de suite de tests pour votre code d'implémentation, tandis que les tests BDD fonctionneront plus ou moins comme des tests d'acceptation pour le client.

26
Robert Harvey

D'après mon expérience, le plus gros problème avec TDD est le " T ". Cela amène le profane (managers, testeurs, développeurs non-TDD) à l'égaler dans leur esprit avec la phase traditionnelle de "test" post-développement d'un style en cascade. C'est quelque chose que tout le monde peut comprendre.

Le problème avec lequel beaucoup de gens se débattent est que TDD est destiné aux développeurs, pas aux testeurs. Bien fait, le TDD n'est pas principalement une stratégie de test ou un outil de test d'acceptation, mais une technique qui stimule une bonne conception logicielle à partir de zéro - de petites classes faiblement couplées, des interfaces claires et bien définies et du code continuellement nettoyé grâce à une refactorisation continue. Refactorisation qui est effectuée régulièrement, fréquemment et à partir d'une position de confiance.

Que vous vous retrouviez avec une suite de tests complète qui peut former une partie de votre processus CI/build est un bonus, pas le but.

BDD complète cela en comblant l'écart entre les exigences commerciales et les tests d'acceptation de niveau supérieur. C'est la satisfaction de la suite BDD qui délimite le processus de développement et qui détermine quand le produit dans son ensemble a été correctement livré.

20
sim303

Les différences entre TDD et BDD sont subtiles et se résument principalement à langue . tests BDD sont souvent écrits sous la forme suivante:

public void shouldBuyBread() throws Exception {
   //given  
   given(seller.askForBread()).willReturn(new Bread());

   //when
   Goods goods = shop.buyBread();

   //then
   assertThat(goods, containBread());
 }  

Si vous encadrez le test en termes de comportement , cela aide à définir la responsabilité de la classe et conduit à une meilleure conception (au moins selon les BDD'ers). BDD se concentre parfois sur les spécifications exécutables que vos experts/clients de domaine peuvent comprendre.

BDD est également plus associé à ce que Martin Fowler appelle des tests "extérieur-dedans" ou "moqueur" , par opposition à la vérification basée sur l'état.

19
Garrett Hall

Étant donné que ma dernière réponse n'a pas été très réussie, je vais essayer une approche très simple.

  • Behaviour Driven Development est un sous-ensemble de Test Driven Development
  • TDD se concentre sur chaque test unitaire pour chaque fonction, peu importe ce qu'il fait. BDD se concentre sur le logiciel qui compte
  • Idiom. TDD s'installe pour les tests, BDD applique histoire format

Exemples JavaScript

Tests unitaires en jasmin (BDD)

describe("A suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });
});

Tests unitaires dans jsUnity (TDD)

function test_lists() { assert.areEqual([1, 2, 3], [1, 2, 3]) }

Voici quelques bibliothèques Python qui aident à créer plus de tests de type BDD avec des frameworks les plus simples:

  • Laitue : Concombre pour python
  • HamCrest
12
percebus

BDD ajoute un niveau d'abstraction supplémentaire aux tests. Le code de niveau supérieur (généralement en txt) décrit ce que le système teste, le code de niveau inférieur décrit comment il le teste. Un framework BDD peut donc utiliser un framework TDD dans le code de niveau inférieur.

Cela aide beaucoup en restant SEC. Avec TDD, vous pouvez facilement vous retrouver avec des tests "humides" contenant beaucoup de duplication de code, ce qui les rend faciles à casser en refactorisant le code et les tests avec. Par BDD, vous devez modifier uniquement le niveau d'abstraction inférieur en refactorisant le code, donc si la spécification ne change pas, le code de niveau supérieur ne changera pas.

Btw. il s'agit d'un simple code propre, généralement il suffit de lire le contenu de niveau d'abstraction élevé pour comprendre ce qu'il fait, et de creuser plus profondément jusqu'au code de test de niveau d'abstraction inférieur uniquement si vous en avez vraiment besoin. Cela rend le code (de test) plus facile à comprendre en général.

Un mauvais exemple (car c'est trop simple):

style jasmin TDD

calculator.add.specs

describe("Calculator: add", function (){

    it("should be able to add 2 numbers together", function (){
        var total = add(1, 2);
        expect(total).toBe(3);
    });

    it("should be able to add 3 numbers together", function (){
        var total = add(1, 2, 3);
        expect(total).toBe(6);
    });
});

style BDD jasmin-concombre

calculator.specs

feature('Calculator: add')
    .scenario('should be able to add 2 numbers together')
        .when('I enter "1"')
        .and('I add "2"')
        .then('I should get "3"')
    .scenario('should be able to add 3 numbers together')
        .when('I enter "1"')
        .and('I add "2"')
        .and('I add "3"')
        .then('I should get "6"')

calculator.steps

featureSteps('Calculator:')
    .before(function(){
        this.values = [];
        this.total = null;
    })
    .when('I enter "(.*)"', function(value){
        this.values.Push(Number(value));
    })
    .when('I add "(.*)"', function(value){
        this.values.Push(Number(value));
    })
    .then('I should get "(.*)"', function(expectedTotal){
        this.total = add.apply(null, this.values);
        expect(this.total).toBe(Number(expectedTotal));
    });

implémentation

calculator.js

function add(){
    var args = Array.prototype.slice.call(arguments);
    var total = 0;
    for (var i in args)
        total += args[i];
    return total;
}

Maintenant, si je renomme la fonction add() en sum() je dois changer le code TDD à 2 endroits, tandis que le code BDD seulement à un seul endroit dans le fichier d'étapes . Ofc. l'ajout d'un niveau d'abstraction supplémentaire nécessite plus de code ...

4
inf3rno

Juste pour garder la confusion, sachez que beaucoup de gens associent désormais le BDD au concombre. Ils considèrent tous les tests que vous écrivez en utilisant la syntaxe dérivée de cornichon comme une vérification BDD, et tout ce qui est écrit en utilisant un cadre de test unitaire (junit, unittest.py, etc.) comme TDD.

C'est faux. Le support ne définit pas le message dans ce cas. Pas plus que l'utilisation de simulacres (IMHO).

La principale différence était déjà donnée: le BDD est une technique axée sur les fonctionnalités, utilisant un langage omniprésent et une approche de l'extérieur vers l'intérieur. Nous écrivons des spécifications (qui seront ensuite exécutées sous forme de tests) pour une histoire ou une tranche d'histoire. La petitesse et le concret sont importants, et c'est une "explication par l'exemple" de ce qui est nécessaire/attendu de cet aspect de l'histoire.

Les spécifications BDD sont fréquemment écrites dans un langage semblable à celui des cornichons si les personnes qui ont besoin de spécifier la fonctionnalité ne lisent pas toutes du code (cas fréquent dans les grandes organisations ou lorsqu'un vrai client fait partie de l'équipe). Sinon, le cornichon n'est pas nécessaire. Celles-ci ont tendance à être le résultat de la célèbre réunion des 3 Amigos: affaires, test, dev tous les faire ensemble. Lorsque vous utilisez un cadre BDD (ajustement, concombre, etc.), les tests sont plus lents et nécessitent un peu plus d'infrastructure, nous les gardons donc relativement rares - quelques-uns par histoire.

TDD est utilisé lors de la création de code. Le but est de donner une progression ordonnée de l'écriture de la fonctionnalité avec de nombreuses opportunités de refactoring et avec une confiance raisonnable que vous ne cassez rien accidentellement lors de l'écriture du nouveau code. Il n'a pas besoin de décrire les caractéristiques du système, seulement une méthode (ou quelques-unes avec un effet commun). Personne, sauf les développeurs, n'a besoin de lire les tests écrits ici, mais ils doivent exécuter des erreurs folles rapidement et isoler les erreurs. Ils fonctionnent très vite car il peut y avoir de nombreux tests par fonction de membre de classe ("méthode").

Si vous faites du BDD sur la couche externe, il est toujours utile de faire du TDD dans la boucle interne en raison du refactoring et de la capacité de repérer et d'éviter les erreurs plus rapidement.

Ce n'est pas non plus une preuve de correction pour un grand système. Aucun ne remplace les tests de stylo et de perf. Aucun n'assure la sécurité des fils. Les tests sont une aide au développement et ne garantissent pas une parfaite protection contre les bogues.

2
tottinge