Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
Commit 72cc7204 authored by Marc's avatar Marc
Browse files

feat: tdd att slides

parent 03897555
No related branches found
No related tags found
No related merge requests found
Pipeline #35178 passed
Showing
with 371 additions and 94 deletions
# Approval Testing + Asciidoctor = BDD + 💕
```shell
cd reveal.js
cd public/reveal.js
npm i
npm run build
```
......
......@@ -7,7 +7,7 @@ import org.approvaltests.scrubbers.RegExScrubber;
import org.approvaltests.scrubbers.Scrubbers;
import org.junit.jupiter.api.Test;
import java.time.*;
import java.time.OffsetDateTime;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
......@@ -24,15 +24,24 @@ class TrucBasiqueTest {
}
// end::truc_approved_basic[]
@Test
void scrubbers_guid() {
var uuid1 = UUID.randomUUID();
var uuid2 = UUID.randomUUID();
Approvals.verify(
"Hello World " + uuid1 + " " + uuid2,
new Options(Scrubbers::scrubGuid)
new Options(
// Scrubbers::scrubGuid
).forFile().withExtension("adoc")
);
}
@Test void html(){
Approvals.verifyHtml("<html><body class=\"polop\">Foo Bar</body></html>");
}
@Test
......@@ -47,7 +56,6 @@ class TrucBasiqueTest {
}
@Test
void scrubbers_regex() {
String input = "Hello " + new Random().nextInt(100) + " World!";
......@@ -70,4 +78,6 @@ class TrucBasiqueTest {
);
}
}
\ No newline at end of file
}
package fr.baldir.exemples.approval.asciidoctor;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.List;
import java.util.Locale;
record Recu(
String magasin,
ZonedDateTime date,
List<LigneArticle> articles
) {
record LigneArticle(String label, float prixHT, float montantTva) {
}
/* float totalHT() {
return (float) Recu.this.articles.stream().mapToDouble(LigneArticle::prixHT).sum();
}
float totalTva() {
return (float) Recu.this.articles.stream().mapToDouble(LigneArticle::montantTva).sum();
}
float totalTTC() {
return totalHT() + totalTva();
}
*/
public String toHumanString() {
var formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT).withLocale(Locale.FRANCE);
var recu = new StringBuilder()
.append("= Reçu").append("\n")
.append("\n")
.append(this.magasin).append("\n")
.append("Le ").append(formatter.format(date)).append("\n")
.append("\n");
var articlesTable = new StringBuilder()
.append("|===").append("\n")
.append("| Article | Prix HT | TVA").append("\n")
.append("\n");
articles.forEach(ligneArticle -> {
articlesTable
.append("|").append(ligneArticle.label).append("\n")
.append("|").append(ligneArticle.prixHT).append("\n")
.append("|").append(ligneArticle.montantTva).append("\n")
.append("\n");
});
articlesTable.append("|===").append("\n");
recu.append(articlesTable).append("\n");
/*
var totalTable = new StringBuilder()
.append("|===").append("\n")
.append("| Total HT | Total TVA | Total TTC").append("\n")
.append("\n")
.append("|").append(totalHT()).append("\n")
.append("|").append(totalTva()).append("\n")
.append("|").append(totalTTC()).append("\n")
.append("\n")
.append("|===").append("\n");
*/
recu
.append("\n")
.append("Merci de votre visite !").append("\n");
return recu.toString();
}
}
package fr.baldir.exemples.approval.asciidoctor;
import org.approvaltests.Approvals;
import org.approvaltests.core.Options;
import org.approvaltests.scrubbers.RegExScrubber;
import org.junit.jupiter.api.Test;
import java.time.ZonedDateTime;
import java.util.List;
public class RecuTest {
@Test
void agile_tour_2024() {
var recu = new Recu(
"Boutique Agile Tour Strasbourg",
ZonedDateTime.now(),
List.of(
new Recu.LigneArticle("T-shirt", 15, 5),
new Recu.LigneArticle("Mug", 5, 2),
new Recu.LigneArticle("Sticker", 1, 0.5F)
));
// Le 24 mai 2024 07:30
Approvals.verify(recu.toHumanString(),
new Options()
// .withScrubber(new RegExScrubber("\\d{2} (.*) \\d{4} \\d{2}\\:\\d{2}", "<Date du reçu>"))
// .forFile().withExtension("adoc")
);
}
}
package fr.baldir.exemples.approval.combination;
import org.approvaltests.combinations.CombinationApprovals;
import org.junit.jupiter.api.Test;
public class CombinationApprovalsTest {
@Test
void test(){
var inputs1 = new String[]{"input1.value1", "input1.value2"};
var inputs2 = new String[]{"input2.value1", "input2.value2", "input2.value3"};
CombinationApprovals.verifyAllCombinations((a, b) -> "placeholder", inputs1, inputs2);
}
}
public/images/approval_attd_01.png

62.7 KiB

public/images/approval_attd_02.png

94.7 KiB

public/images/approval_attd_03.png

142 KiB

public/images/approval_attd_04.png

145 KiB

public/images/approval_attd_05.png

155 KiB

public/images/approval_attd_06.png

160 KiB

public/images/approval_attd_07.png

176 KiB

public/images/approval_attd_08.png

181 KiB

public/images/baldir-me-qr-code.png

55.3 KiB

This diff is collapsed.
......@@ -35,37 +35,126 @@
:docinfo: private
// :docinfodir: {outdir}
//
//
// == Connect
//
// Quelles techniques de test pouvez-vous nommer ?
//
//
// == Marc Bouvier
//
// == Concept
//
// Un framework de test écrit par Llewellyn Falco
//
// Basé sur l'idée du Golden master(REF).
//
// Représenter dans un fichier test les sorties de l'exécution d'un programme.
//
// Le résultat est approuvé par un humain.
//
// C'est un type d'assertion.
== Cas d'utilisation
== Avez-vous déjà ?
[%step]
[NOTE]
====
Rencontré une base de code sans tests ?
====
[%step]
[NOTE]
====
Trouvé du code difficile à refactorer ?
====
[%step]
[NOTE]
====
Des assertions difficiles à faire sur des documents ou modèles de données complexes ?
====
[%step]
[NOTE]
====
Eu des difficultés à communiquer avec le métier sur le comportement du code ?
====
== Approval testing Assertions
Outil qui simplifie les assertions de documents et modèles d'objets complexes
[%step]
1. On écrit un test avec une assertion de Approvals
2. Jouer le test la première fois génère
** un fichier "approuvé" vide
** un fichier "reçu" avec le résultat du test
3. Rejouer le test compare les 2 fichiers
4. Approuver le résultat si il nous convient
5. Si les 2 fichiers sont identiques le test passe
[%step]
En gros c'est ça !
[.columns]
== Marc Bouvier
[.column]
--
[%steps]
* Coach Technique
* Développeur Généraliste
* A11Y
--
[.column]
--
* https://iroco.co
* https://meetup.com/software-crafters-strasbourg
* https://u.baldir.fr/me
image::baldir-me-qr-code.png[QR code Marc Bouvier,width=300]
--
== Cas d’utilisation
[%steps]
* Caractérisation de code existant
* Verrouiller pour Refactor du Code Legacy
* Test Driven Development
* Acceptance Test Driven Development
* Locking of Code for refactoring (ex. Code legacy)
* REST API
* IHM
== Caractérisation de code existant
[NOTE]
====
Peut être pertinent quand la connaissance métier a été diluée ou oubliée.
== TDD avec Approval
Les règles métier sont dans le code. Rendons les explicites
====
[%step]
* Isoler un bout de code dans un filet de test
* Ecrire une assertion qui échoue
* Executer le test
* Changer le test pour qu'il corresponde au résultat
* Répter jusqu’à être relativement sûr·e que tous les degrés de libertés sont identifiés et testé
* Nommer le test selon le comportement caractérisé
== Verrouiller pour Refactor du Code Legacy
[NOTE]
====
Peut être pertinent quand un code n'est pas du tout testé et qu’on veut le refactorer.
Et on ne sait pas par où commencer.
====
De façon similaire à la caractérisation
[%step]
* Isoler un bout de code dans un filet de test
* Ecrire des tests pour couvrir un maximum de branches
* Refactorer
* Au fur et à mesure du refactoring on peut ajouter des tests plus petits
* (bonus) lancer des tests de mutation peut permettre de détecter du code mort ou des assertions manquantes
* Jeter les tests de verrouillage
== Test Driven Development
Les assertions "Approval" peuvent être utilisées dans un flow TDD footnote:TDD[Test Driven Development]
C'est à dire qu'on écrit d'abord un test qui échoue et on écrit le code de production pour qu'il passe.
[%notitle]
=== Réfléchir au comportement qu'on attend
......@@ -218,17 +307,55 @@ image::approval_tdd_11_final_green.png[]
[%notitle]
=== Foo
== Locking Code for refactoring of Legacy Code
== Acceptance Test Driven Development
[%notitle]
=== foo
image::approval_attd_01.png[]
[%notitle]
=== foo
image::approval_attd_02.png[]
[%notitle]
=== foo
image::approval_attd_03.png[]
[%notitle]
=== foo
image::approval_attd_04.png[]
[%notitle]
=== foo
image::approval_attd_05.png[]
Ajouter des tests autour de code pour rendre le refactoring possible
[%notitle]
=== foo
image::approval_attd_06.png[]
[%notitle]
=== foo
💡 Idée d'image d'une troupe d'enfants qui posent plein de questions à un programme
image::approval_attd_07.png[]
[%notitle]
=== foo
=== Caractérisation
image::approval_attd_08.png[]
// TODO: refactoring Kata
== Propriétés
......@@ -240,6 +367,9 @@ Ajouter des tests autour de code pour rendre le refactoring possible
- Il est facile de mettre à jour les résulats attendus (à l'aide de nos outils de diff)
- On sait facilement où on en est : on peut comparer à notre brouillon sur papier ou tableau blanc
- On peut éviter des abstractions prématurées qui pourraient se coupler dans nos tests
- Binomer avec les gens du métier
- Eviter des développer des IHM trop tôt
====
[WARNING]
......@@ -349,6 +479,9 @@ image::approvals_attd_java_01_blank_diff.png[]
include::exemples/java/exemples-java/src/test/java/fr/baldir/exemples/approval/FizzBuzzAttdTest.java[tag=approvals_attd_01]
----
== Approvals + Asciidoctor
== Et BDD dans tout ça?
......@@ -386,47 +519,47 @@ include::exemples/java/exemples-java/src/test/java/fr/baldir/exemples/approval/F
** https://www.youtube.com/watch?v=vMww6pV6P7s&list=PL7GpAlmbnHyAOQfqrF9-HXFIG45LvPKy_[Emily Bache — Approval Testing playlist]
** https://blog.approvaltests.org/2012/05/testing-circle.html[The Testing Circle]
== Asciidoc quick refs
== Inclusion
Exemple d'inclusion
[source]
----
include::exemples/test.txt[]
----
=== Image
Exemple d'image
image::exemple_image.png[]
=== Tableau
|===
| Header Cell 1 | Header Cell 2
| Row 1 Cell 1
| Row 1 Cell 2
| Row 2 Cell 1
| Row 2 Cell 2
|===
== Footnotes
Gilded Rose Kata footnote:gilded_rose_kata[truc]
== Pulip
=== Baz
== Pelep
\ No newline at end of file
//
// == Asciidoc quick refs
//
// == Inclusion
//
// Exemple d'inclusion
//
// [source]
// ----
// include::exemples/test.txt[]
//
// ----
//
// === Image
//
// Exemple d'image
//
// image::exemple_image.png[]
//
// === Tableau
//
//
// |===
// | Header Cell 1 | Header Cell 2
//
// | Row 1 Cell 1
// | Row 1 Cell 2
//
// | Row 2 Cell 1
// | Row 2 Cell 2
// |===
//
//
// == Footnotes
//
// Gilded Rose Kata footnote:gilded_rose_kata[truc]
//
// == Pulip
//
//
//
// === Baz
//
// == Pelep
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment