Lorsqu’on écrit nos tests unitaires, on peut avoir l’impression que certains cas de tests sont quasiment identiques dans leur structure. Ils sont rébarbatifs à lire/écrire. C’est là que la notion de dataProvider est utile: on va réutiliser le même test mais avec des paramètres d’entrée différents 😉
On a le premier joueur qui marque x fois, le second joueur qui marque x fois et enfin on compare avec le résultat attendu.
Les tests peuvent vite se multiplier et se ressembler:
@Test
void shouldBe15LoveWhenPlayerOneScore() {
Game game = new Game();
game.playerOneScoresAPoint();
String score = game.printScore();
assertThat(score).isEqualTo("15 - LOVE");
}
@Test
void shouldBe15-15WhenBothPlayersScore() {
Game game = new Game();
game.playerOneScoresAPoint();
game.playerTwoScoresAPoint();
String score = game.printScore();
assertThat(score).isEqualTo("15 - 15");
}
@Test
void shouldBe30LoveWhenPlayerOneScore() {
Game game = new Game();
game.playerOneScoresAPoint();
game.playerOneScoresAPoint();
String score = game.printScore();
assertThat(score).isEqualTo("30 - LOVE");
}
C’est assez rébarbatif et on se retrouve rapidement avec une classe de test qui fait plusieurs dizaines / centaines de lignes. On va voir dans cet article comment rendre nos tests plus lisibles et maintenables grâce aux tests paramétrés 😀
Cette bibliothèque va nous permettre de passer des paramètres d’entrées à nos tests. Ces paramètres proviendront d’une source de données (une méthode, un CSV, un tableau etc..).
Pour marquer un test comme un test paramétré, on va utiliser l’annotation @ParametrizedTest.
Exemple:
@ParameterizedTest
void shouldGetGameScore(int timesPlayerOneScores, int timesPlayerTwoScores, String expectedGameScore) {
Ensuite, on doit décrire d’où proviennent les données d’entrées (notre data-provider) avec une autre annotation.
Avec @MethodSource j’indique que mes données viennent de la méthode nommée “gameProvider”.
Exemple:
@ParameterizedTest
@MethodSource("gameProvider")
void shouldGetGameScore(int timesPlayerOneScores, int timesPlayerTwoScores, String expectedGameScore) {
Un test unitaire sera exécuté par chaque argument. Par exemple, pour le premier argument Arguments.of(0, 0, « LOVE – LOVE »), mon test unitaire sera lancé avec:
– Le premier paramètre (timesPlayerOneScores) qui vaut 0
– Le second paramètre (timesPlayerTwoScores) qui vaut 0 également
– Le dernier paramètre (expectedGameScore) qui a pour valeur “LOVE – LOVE”
Note: D’autres façons de transmettre de la donnée existent. On peut lire un CSV, une énum ou même donner un tableau d’entrée.
Exemple concret du cas d’usage décrit en introduction
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
class TennisTest {
private Game game;
@ParameterizedTest
@MethodSource("gameProvider")
void shouldGetGameScore(int timesPlayerOneScores, int timesPlayerTwoScores, String expectedGameScore) {
game = new Game();
playerOneScores(timesPlayerOneScores);
playerTwoScores(timesPlayerTwoScores);
String score = game.printScore();
assertThat(score).isEqualTo(expectedGameScore);
}
private void playerOneScores(int timesPlayerOneScores) {
for (int i = 0; i < timesPlayerOneScores; i++) {
game.playerOneScoresAPoint();
}
}
private void playerTwoScores(int timesPlayerTwoScores) {
for (int i = 0; i < timesPlayerTwoScores; i++) {
game.playerTwoScoresAPoint();
}
}
public static Stream<Arguments> gameProvider() {
return Stream.of(
Arguments.of(0, 0, "LOVE - LOVE"),
Arguments.of(1, 0, "15 - LOVE"),
Arguments.of(2, 0, "30 - LOVE"),
Arguments.of(3, 0, "40 - LOVE"),
Arguments.of(0, 1, "LOVE - 15"),
Arguments.of(2, 3, "30 - 40"),
Arguments.of(3, 3, "DEUCE")
);
}
}
En lançant mes tests, on a bien le détail de l’exécution:
Conclusion
Si vous avez la sensation d’écrire plusieurs fois des tests similaires, un test paramétrés pourra peut-être vous permettre de gagner en temps d’écriture et en lisibilité. C’est un outil que j’utilise au quotidien et j’espère que je vous aurais convaincu de son intérêt 😀
Votre changelog reprend les fonctionnalités que vous avez réalisé entre deux versions, ça tombe bien, votre historique git contient ces informations :) On va voir comment les extraire de git pour générer automatiquement un changelog exhaustif et fiable.
Le principe
Pour faciliter la maintenance de votre projet, il est d’usage d’avoir des commits parlants afin que tous les d...
Photo by Yancy Min on Unsplash
Contexte
Je suis développeur au quotidien et j'aime développer en dehors du travail également.
Parfois, il peut m’arriver de faire un kata entre midi et deux par exemple. J'aime bien du coup garder une trace de mon exerc...
On va prendre un cas concret: j’ai fait un commit et en relisant ma merge request, je me rend compte que certains fichiers ne devraient pas y être:
Dans mon cas c’est le fichier src/test/java/com/globaldashboard/unit/dependencies/domain/PomUrlTest.java
...
Dans une application Spring, sauf exceptions, les Beans sont proxifiés. En d’autres mots, on n'interagit pas directement avec eux et ce mécanisme est à la base de l’AOP.
Beaucoup de mécanismes s'appuient sur l’AOP (les Transactions par exemple) et conn...