web-dev-qa-db-fra.com

Développement piloté par les tests - Comment écrire un test avant qu'aucun code d'implémentation n'existe

J'apprends le TDD mais j'ai du mal à l'adopter car ce n'est pas simple.

La question à laquelle je ne peux pas répondre est "Comment écrire un test avant qu'un code d'implémentation existe?".

Si notre classe cible/méthode cible/type de paramètre cible/type de retour cible n'existe pas,

  • À quoi faisons-nous référence lors de l'écriture de code dans le test. Comment commençons-nous à écrire le test?
  • Comment le test a-t-il échoué si nous ne pouvions écrire que le nom de la méthode de test avant le code d'implémentation réel?

Tout le monde dit POURQUOI mais pas COMMENT

J'ai fait de mon mieux pour trouver des ressources qui élaborent sur l'écriture de tests avant le code de production mais, en supposant que j'ai manqué de bonnes ressources, la plupart d'entre elles sont remplies de clichés expliquant pourquoi le TTD est important que de se concentrer sur les pratiques pour l'adopter.

n exemple de cas d'utilisation.

Supposons que nous développons un logiciel pour une université et notre cas d'utilisation est l'inscription aux cours.

Pour faire simple, limitons cette discussion à

  • scénario: "Un étudiant peut s'inscrire à un maximum de 3 cours par semestre"
  • tester la couche de service et la couche dao.

Pseudocode

ENROLL(studentId, courseId)
    //check if student enrolled in less than 3 courses in the same semester as given courseId belongs in.
    //if yes, enroll him/her.
    //if not, return an error.

La mise en œuvre réelle de ce qui précède pourrait s'étendre sur quelques classes impliquant des services, des daos, etc.

Pourriez-vous expliquer comment le piloter par les tests, le développer étape par étape? Si vous deviez l'implémenter à l'aide de TDD, comment l'auriez-vous fait étape par étape.

J'espère que cela pourrait aider de nombreuses luttes comme moi à l'avenir.

48
phani

Créez la classe EnrollingServiceTest dans src/test/Java dans le même package que EnrollingService

class EnrollingServiceTest {
    private EnrollingService enrollingService;

    @Before 
    public void init() {
           enrollingService = new EnrollingService();
    }

    @Test
    public void testEnroll() {
           boolean result = enrollingService.enroll(1l, 1l);
           assertTrue(result);
    ...

IDE (je suppose que vous utilisez IDE) affiche des erreurs - EnrollingService n'existe pas.

Pointez le curseur sur EnrollService - IDE proposera de créer une classe - laissez-le créer dans src/main/Java

Maintenant IDE dit que la méthode d'inscription (longue, longue) est manquante - laissez IDE la créer pour vous).

Maintenant IDE ne montre aucune erreur. Exécutez le test - il échoue. Accédez à l'inscription et commencez à implémenter la logique

Etc...

43
Evgeniy Dorofeev

Cela deviendra plus clair lorsque vous vous concentrerez sur le comportement attendu du code plutôt que sur l'implémentation du code. Donc, étant donné le scénario que vous avez décrit, vous pouvez arriver à la conclusion que vous devrez écrire la méthode enroll () dans une classe. Vous pouvez ensuite examiner comment vous allez tester cette classe.

Vous commencez par considérer les conditions de la classe et ce que l'on attend d'elle. Vous pouvez peut-être identifier certains invariants de la classe. Dans ce cas, pour tester la classe, vous considérez les façons dont cet invariant peut être violé.

Donc, en prenant la déclaration: un étudiant peut s'inscrire à un maximum de 3 cours par semestre, vous considérez les façons dont cela peut se produire.

  1. L'étudiant est inscrit à 0 cours pour le semestre donné, tentative d'inscription à un cours, résultat: inscription réussie; l'étudiant est maintenant inscrit à 1 cours pour le semestre donné.
  2. L'étudiant est inscrit à 1 cours pour un semestre donné, essayez de vous inscrire à un cours, résultat: inscription réussie; l'étudiant est maintenant inscrit à 2 cours pour le semestre donné.
  3. L'étudiant est inscrit à 3 cours pour le semestre donné, essayez de vous inscrire à un cours, résultat: échec (peut-être une exception est levée?)
  4. etc

Ensuite, vous écrivez réellement ces tests. Chacun d'eux peut être une méthode d'essai. Ainsi, la méthode de test garantirait que les objets sont créés et l'environnement est configuré comme prévu. Appelez ensuite la méthode et comparez le résultat au résultat attendu. Si ce que vous attendez se produit réellement, le test a réussi.

Maintenant, au départ, puisque vous n'avez pas encore écrit la méthode, les tests ne réussiront pas réellement. Mais au fur et à mesure que vous commencez à écrire du code, vos tests commenceront à passer et, à terme, 100% de vos tests passeront à quel point vous êtes convaincu que votre code répond aux exigences.

4
Vincent Ramdhanie
public void shouldNotEnrollInMoreThanFourClassesInASemester() {
  Enroller enroller = new Enroller();
  Student student = new Student();
  Semester one = new Semester();
  Semester two = new Semester();
  Course geology = new Course(one);
  Course architecture = new Course(one);
  Course calculus = new Course(one);
  Course sociology = new Course(one);
  Course geometry = new Course(two);

  assertOk(enroller.enroll(student, geology));
  assertOk(enroller.enroll(student, architecture));
  assertOk(enroller.enroll(student, calculus));
  assertNotOk(enroller.enroll(student, sociology));
  assertOk(enroller.enroll(student, geometry));
}
3
Carl Manaster

Dans votre scénario, vous devez tester chaque couche séparément, alors moquez-vous du DAO lors du test de la couche de service.

Lorsque vous écrivez le test pour la première fois, il ne sera pas compilé, ce qui signifie qu'il échoue, mais c'est bien car les classes n'existent pas.

Dans votre exemple, quelle couche appliquer pour s'inscrire à 3 cours au maximum? Cela affectera la façon dont vous testez.

Écrire d'abord le test vous aidera à résoudre ces types de questions.

Comme cela a été mentionné, cela est trop ouvert pour une réponse définitive, mais si vous commencez à écrire votre test, puis postez une mise à jour, cela pourrait aider.

Donc, écrivez votre test dao puis écrivez les classes et les méthodes pour qu'il compile mais il devrait toujours échouer jusqu'à ce que yiu termine l'implémentation. Vous souhaiterez probablement tester les enregistrements de classe 2,3,4 et vous assurer que chacun échoue correctement, puis terminer l'implémentation.

1
James Black