<style>
.reveal {
font-family: Roboto, Source Sans Pro, Helvetica, sans-serif;
font-size: 42px;
font-weight: 300;
}
.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5,
.reveal h6 {
margin: 0 0 20px 0;
font-family: Roboto, Source Sans Pro, Helvetica, sans-serif;
font-weight: 500;
line-height: 1.2;
letter-spacing: normal;
text-transform: uppercase;
text-shadow: none;
word-wrap: break-word;
}
.reveal section img {
margin: initial !important;
background: initial !important;
border: initial !important;
box-shadow: initial !important;
}
</style>
# Du test logiciel au TDD
---
## Marc Gavanier
<img style="border-radius: 50%;" src="https://2.gravatar.com/avatar/e500c6fc2a4df90cb99b2a249b6f737c?s=150&d=mm">
Efrei
<small>Promotion 2014</small>
Développeur indépendant
<small>En mission chez [beta.gouv](https://beta.gouv.fr/)
pour la [cartographie nationale des lieux de médiation numérique](https://cartographie.societenumerique.gouv.fr)
</small>
...
<small>[LinkedIn](https://www.linkedin.com/in/marc-gavanier/) | [GitHub](https://github.com/marc-gavanier)</small>
---
## Pyramide des tests
---
<img src="https://i.ibb.co/D1Kzc1T/software-testing-fr.png">
---
## Outils de test - web / JS
- Tests manuels et exploratoires : [Souris et clavier](https://www.cdiscount.com/informatique/clavier-souris-webcam/pack-corsair-clavier-gamer-membrane-k55-rgb-pro/f-1070299-bun21cor30.html#mpos=0|cd)
- Tests de bout en bout : [Cypress](https://www.cypress.io/)
- Tests d'acceptation : [Cucumber](https://cucumber.io/)
- Tests d'UI et d'API : [Storybook](https://storybook.js.org/) & [Insomnia](https://insomnia.rest/product/automated-testing)
- Tests d'intégration : [Jest](https://jestjs.io/)
- Tests unitaires : [Jest](https://jestjs.io/)
---
## Tests unitaires
---
### AAA / GWT
Arrange-Act-Assert
Given-When-Then
*Quelle est la structure d'un test unitaire ?*
---
#### A / G
Arrange / Given
Écrire le code nécessaire à la mise en place du test à exécuter.
```typescript=
const userId: Id = Id('f4b5az654fzb65a4');
const roles: Role[] = [];
const user: User = createUser(userId, roles);
const adminRole: Role = Role.Admin;
```
---
#### A / W
Act / When
Appeler le système que l'on souhaite tester.
```typescript=
const adminUser: User = setRole(user, adminRole);
```
---
#### A / T
Assert / Then
Vérifier que le retour correspond à ce qui est attendu.
```typescript=
expect(adminUser.roles).toContain(adminRole);
```
---
#### Exemple complet
```typescript=
const userId: Id = Id('f4b5az654fzb65a4');
const roles: Role[] = [];
const user: User = createUser(userId, roles);
const adminRole: Role = Role.Admin;
const adminUser = setRole(user, adminRole);
expect(adminUser.roles).toContain(adminRole);
```
---
### FIRST
*Quelles sont les caractéristiques d'un test unitaire ?*
---
#### F
Fast
Tous les tests doivent s'exécuter en quelques millisecondes.
Plusieurs centaines de tests unitaires ne devraient pas prendre plus de quelques secondes.
Une boucle de rétroaction rapide permet aux développeurs de lancer les tests unitaires en continue pendant la rédaction du code tout en ayant un retour quasi immédiat sur ce qui vient d'être ajouté.
---
#### I
Independent / Isolated
Les tests ne doivent pas dépendre les uns des autres. Tout ce que le test doit exécuter doit lui être configuré spécifiquement afin d'éviter les effets de bord.
Les tests doivent garantir que leurs résultats sont uniquement obtenus à partir d'un état initial donné qui peut facilement être mis à jour.
---
#### R
Repeatable
Chaque fois qu'un test est exécuté seul ou dans une suite de tests, on devrait observer le même comportement. Il doit être déterministe et sans aucun traitement conditionnel.
---
#### S
Self-validating
La seule information utile qu'un test fournit est s'il réussit ou s'il échoue.
Aucune autre vérification ne devrait être effectuée pour connaître l'état réel du résultat d'un test. Par exemple la vérification manuelle des informations écrites dans un fichier est à proscrire.
---
#### T
Thorough (Minutieux / Complet)
L'ensemble des tests d'une fonctionnalité, devraient couvrir la totalité des scénarios envisageables.
Aussi bien les chemins prévus lorsque tout se passe comme attendu, mais également les cas aux limites et les cas d'échec.
---
### Couverture de code
---
Quand un test est lancé, seules certaines parties du code sont effectivement appelées.
La **couverture de code** indique précisément quelles instructions ont été appelées au cours de l'exécution d'un test.
---
En faisant la somme de tous les chemins de code parcourus par l'ensemble des tests, on peut facilement détecter le code qui n'a été appelé par aucun test.
---
### TDD
Test Driven Development
(Développement **PILOTÉ** par les tests)
---
TDD n'est **PAS** test after
TDD n'est **PAS** test first
---
<img height="500" src="https://i.imgflip.com/6x56t9.jpg">
---
Quelques alternatives courantes au TDD :
- Navigateur + F5
- `console.log(result);`
- `console.log('here 5/8');`
- `console.log('please work 🙏', i);`
- 🔴
---
#### Red, Green, Refactor
<img width="600" src="https://i.ibb.co/mGZGQZ8/TDD-red-green-refactor-FR.png">
---
### Baby steps
Incite à faire de petits cycles Red-Green-Refactor.
---
Faire de longues itérations implique une plus grande charge cognitive pour faire passer les tests.
Finalement cela conduit à une mauvaise conception, au mieux avec du code inutile et au pire avec des erreurs.
---
À l'inverse faire de courtes itérations aide à rester focalisé sur un objectif simple, ouvre la voie vers une conception émergente et permet d'avoir plus tôt des validations sur le code qui est en train d'être rédigé.
---
### ZOMBIES
*Par où commencer lorsque l'on veut écrire un test ?*
---
<img width="600" src="https://i.ibb.co/7zbpgKY/zombies-2-D.png">
---
#### Z
Zero
Commencer par résoudre les problèmes simples.
*Que se passe-t-il lorsque le tableau est vide ?*
---
#### O
One
Lorsque tout est en place pour répondre au cas le plus simple possible, il est temps de passer à l'action la plus simple qui puisse être faite.
*Que se passe-t-il lorsque le tableau ne contient qu'un élément ?*
---
#### M
Many
Maintenant que les scénarios de base ont été explorés, il est temps de traiter des cas plus complexes.
*Que se passe-t-il lorsque le tableau contient plusieurs éléments dont l'un d'entre eux doit être ignoré ?*
---
#### B
Boundary Behaviors
Les cas par défaut sont faciles à imaginer, mais les comportements marginaux sont souvent oubliés et peuvent conduire à des comportements inattendus une fois en production.
Boundaries Behaviors est là pour rappeler que les tests doivent également couvrir ces cas.
*Que se passe-t-il lorsque le tableau contient un élément en double et que l'on souhaite éviter de répéter deux fois le même traitement ?*
---
#### I
Interface definition
L'écriture d'un test est un bon moment pour réfléchir à la manière dont on souhaite appeler une fonctionnalité donnée.
On peut aller plus loin dans ce principe et se servir des tests pour essayer différentes façons d'appeler le code et ainsi découvrir ce qui est le plus pratique.
---
#### E
Exercise Exceptional behavior
Une fois les cas communs et les cas particuliers définis, il manque encore les cas qui conduisent à des erreurs.
*Que se passe-t-il lorsque le tableau n'est pas initialisé et pointe vers une référence nulle ?*
---
#### S
Simple Scenarios, Simple Solutions
Quel que soit le test, il doit appliquer une solution simple à un scénario simple et bien défini.
En respectant cela, les tests sont simples à écrire, simples à comprendre et simples à mettre à jour.
---
## References
- [Unit Testing and the Arrange, Act and Assert (AAA) Pattern](https://medium.com/@pjbgf/title-testing-code-ocd-and-the-aaa-pattern-df453975ab80)
- [F.I.R.S.T principles of testing](https://medium.com/@tasdikrahman/f-i-r-s-t-principles-of-testing-1a497acda8d6)
- [TDD Guided by ZOMBIES](http://blog.wingman-sw.com/tdd-guided-by-zombies)
- [Code Coverage](https://www.educba.com/code-coverage/)
- [Baby Steps in TDD](https://medium.com/@heaton.cai/baby-steps-in-tdd-7761ad362e34)
{"metaMigratedAt":"2023-06-17T11:54:30.506Z","metaMigratedFrom":"YAML","title":"Du test logiciel au TDD","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"controls\":false,\"progress\":true,\"slideNumber\":false}","contributors":"[{\"id\":\"01d6a5d9-edd0-4d27-b734-061799130618\",\"add\":12707,\"del\":4191}]"}