SlideShare una empresa de Scribd logo
1 de 21
Descargar para leer sin conexión
BBL sur les tests
JUnit, Mockito, AssertJ
Une petite soif ? Sirotez donc un mockito (sans alcool bien sûr :p) en écoutant CE BBL!
Par Idriss Neumann, le 11/02/2016
Sommaire
❖ Généralités
➢ Pourquoi écrire des tests ?
➢ Différence entre TI et TU
➢ Démarche du TDD
❖ Le framework JUnit
➢ Définition
➢ Structure d’un test case
➢ Les différentes assertions
➢ Assertions sur exception
❖ L’alternative AssertJ
❖ Les objets simulacres
➢ Différences entre mock et stub
➢ Liste des mocking toolkits
❖ Le framework Mockito
➢ Créer un mock
➢ Prédire le résultat d’une méthode d’un mock
➢ Faire des assertions sur l’invocation d’un mock
➢ L’utilisation des annotations
➢ Les arguments captors
➢ Les espions (spy)
❖ Question
Généralités
Pourquoi écrire des tests ?
Écrire des scénarios de tests automatisés (tant des tests unitaires que des tests d'intégration) constitue une étape incontournable
du cycle de développement logiciel dans un cadre professionnel.
Bien que cette tâche puisse parfois sembler rébarbative, elle est indispensable pour produire des développements de bonne
qualité, notamment parce que cela permet entre autres de :
❖ s'assurer que l'on maîtrise les aspects fonctionnels de l'application (les besoins métier à satisfaire) ;
❖ détecter au plus tôt les anomalies éventuelles avant la livraison d'un projet aux utilisateurs ;
❖ détecter d'éventuelles régressions, suite à l'implémentation de nouvelles fonctionnalités, en automatisant l'exécution de
l'ensemble de tous les scénarios de tests implémentés sous forme de tests unitaires ou tests d'intégration, de façon à ce
qu'ils soient exécutés régulièrement (à minima une fois par jour par exemple).
Plus l'ensemble de vos codes sera couvert par les tests, plus vous serez à même de détecter les régressions, de maîtriser
l'ensemble des fonctionnalités de votre application et ainsi de la rendre plus maintenable.
Généralités
Différence entre tests unitaires et tests d’intégration
De manière générale, le test unitaire a pour but de tester une partie précise d'un logiciel (d'où le nom "unitaire") voire une
fonction précise, en essayant de couvrir au maximum la combinatoire des cas fonctionnels possibles sur cette portion de code.
Cependant, cela ne suffit pas à différencier un test unitaire d'un test d'intégration qui, lui aussi, peut se contenter de tester une
portion précise du code.
La différence fondamentale est que le test unitaire doit uniquement tester le code et ne doit donc pas avoir d'interactions avec
des dépendances externes du module testé telles que des bases de données, des Web services, des appels à des procédures
distantes, la lecture ou écriture de fichiers ou encore d'autres fonctions. Les dépendances devront être simulées à l'aide de
mécanismes tels que les bouchons ou encore les mocks.
Concernant les tests d'intégration, ceux-ci permettent, de manière générale, de vérifier la bonne intégration de la portion de code
testée dans l'ensemble du logiciel et de ses dépendances. Il peut s'agir tout aussi bien de vérifier la bonne insertion de données
dans un SGBDR sur une petite portion de code que de scénarios complets du logiciel, correspondant à des enchaînements
d'appels de fonctions, de Web services... (c'est ce que l'on appelle aussi des tests « bout en bout »).
Généralités
La démarche du TDD
TDD est un acronyme pour « Test Driven Development » ou encore le développement dirigé par les tests en français. Il s'agit
d'une démarche qui recommande au développeur de rédiger l'ensemble des tests unitaires avant de développer un logiciel ou les
portions dont il a la charge.
Cette démarche permet de s'assurer que le développeur ne sera pas influencé par son développement lors de l'écriture des cas
de tests afin que ceux-ci soient davantage exhaustifs et conformes aux spécifications. Ainsi, cette démarche permet aussi de
s'assurer que le développeur maîtrise les spécifications dont il a la charge avant de commencer à coder.
L'approche TDD préconise le cycle court de développement en cinq étapes :
1. écrire les cas de tests d'une fonction ;
2. vérifier que les tests échouent (car le code n'existe pas encore) ;
3. développer le code fonctionnel suffisant pour valider tous les cas de tests ;
4. vérifier que les tests passent ;
5. refactoriser et optimiser en s'assurant que les tests continuent de passer.
Le framework JUnit
Qu’est-ce que JUnit
JUnit est un framework Java prévu pour la réalisation de tests unitaires et d'intégration.
JUnit est le framework le plus connu de la mouvance des frameworks xUnit implémentés dans de nombreuses technologies (nous
pourrons également citer PHPUnit pour PHP ou encore xUnit.NET pour C# et .NET par exemple).
JUnit permet de réaliser :
❖ des TestCase qui sont des classes contenant des méthodes de tests ;
❖ des TestSuite qui permettent de lancer des suites de classes de type TestCase.
Voir la slide suivante pour avoir la structure globale d’une classe de test écrite en JUnit >= 4.
Le framework JUnit
import org.junit.Before;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.AfterClass;
import org.junit.Test;
public class MaClasseDeTest {
/** Pre et post conditions */
@BeforeClass
public static void
setUpBeforeClass() throws Exception
{
// Le contenu de cette
méthode ne sera exécuté qu'une fois
avant toutes les autres méthodes
avec annotations
// (y compris celles ayant
une annotation @Before)
}
@AfterClass
public static void tearDownClass()
throws Exception {
// Le contenu de cette méthode
ne sera exécuté qu'une fois après
toutes les autres méthodes avec
annotations
// (y compris celles ayant une
annotation @After)
}
@Before
public void setUp() throws
Exception {
// Le contenu de cette méthode
sera exécuté avant chaque test (méthode
avec l'annotation @Test)
}
@After
public void tearDown() throws
Exception {
// Le contenu de cette méthode
sera exécuté après chaque test (méthode
avec l'annotation @Test)
}
/** Cas de tests */
@Test
public void testCas1() {
// Code contenant l'exécution du
premier scénario avec les assertions
associées
}
@Test
public void testCas2() {
// ...
}
}
Le framework JUnit
Les différents types d’assertions avec JUnit
En informatique, une assertion est une expression qui doit être évaluée vrai ou faire échouer le programme ou le test en cas d’
échec (en levant une exception ou en mettant fin au programme par exemple).
Dans le cas de JUnit et des tests d'une manière générale, on peut assimiler une assertion à une vérification et, en cas d’échec, une
exception spécifique est levée (java.lang.AssertionErrorpour JUnit).
Voici une liste non exhaustive des fonctions d'assertions en JUnit :
● assertEquals: vérifier l'égalité de deux expressions ;
● assertNotNull: vérifier la non-nullité d'un objet ;
● assertNull: vérifier la nullité d'un objet ;
● assertTrue: vérifier qu'une expression booléenne est vraie ;
● assertFalse: vérifier qu'une expression booléenne est fausse ;
● fail : échouer le test si cette assertion est exécutée.
Ces méthodes sont surchargées pour de nombreux objets. Par exemple, la méthode assertEquals va être surchargée pour tous les
types primitifs et pour les classes implémentant la méthode equals (String par exemple). Il est également possible de fournir un
message d'erreur en cas d'échec d'une assertion (en premier paramètre).
Le framework JUnit
Exemples d’assertions simples
Imaginons que l’on veuille tester la classe suivante :
public class Addition {
Integer nb1, nb2;
public Addition(Integer nb1, Integer nb2){
this.nb1 = nb1;
this.nb2 = nb2;
}
public Integer somme(){
return nb1 + nb2;
}
public Integer getNb1() {
return nb1;
}
public Integer getNb2() {
return nb2;
}
}
Voici un exemple de fonction de test :
@Test
public void testCasAdditionNominal() {
Addition add = new Addition(1, 2);
// vérification, on a bien valorisé l'attribut nb1
assertEquals(1, add.getNb1());
// vérification, on a bien valorisé l'attribut nb2
assertEquals(2, add.getNb2());
// vérification sur la méthode somme()
assertEquals("Erreur dans le calcul de la somme",
3, add.somme());
}
Remarque : les imports statiques sont préconisés pour les méthodes statiques
provenant des frameworks de tests présentés dans ce BBL.
Le framework JUnit
Exemples d’assertions sur des exceptions
Il est possible de vérifier la levée d'une exception grâce à l'annotation @Test(expected=<nom>.class) :
// Ce test va réussir
@Test(expected = java.lang.NullPointerException.class)
public final void testException(){
Long variablePasInstanciee = null;
variablePasInstanciee.toString();
}
// Ce test va échouer
@Test(expected = java.lang.NullPointerException.class)
public final void testException2(){
Long variableInstanciee = 1L;
variableInstanciee.toString();
}
L’alternative AssertJ
Une alternative aux assertions JUnit sont les assertions d’AssertJ, une librairie mettant à disposition des assertions tout en
adoptant le “fluent code style”. Il s’agit de la syntaxe préconisée sur le projet Hub numérique.
Voici des exemples d’assertions issues de la documentation officielle d’AssertJ:
// unique entry point to get access to all assertThat methods and utility methods (e.g. entry)
import static org.assertj.core.api.Assertions.*;
// basic assertions
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron)
.isIn(fellowshipOfTheRing);
// String specific assertions
assertThat(frodo.getName()).startsWith("Fro")
.endsWith("do")
.isEqualToIgnoringCase("frodo");
// collection specific assertions
assertThat(fellowshipOfTheRing).hasSize(9)
.contains(frodo, sam)
.doesNotContain(sauron);
L’alternative AssertJ
// using extracting magical feature to check fellowshipOfTheRing characters name :)
assertThat(fellowshipOfTheRing).extracting("name")
.contains("Boromir", "Gandalf", "Frodo", "Legolas")
.doesNotContain("Sauron", "Elrond");
// Extracting with Java 8 love (type safe)
assertThat(fellowshipOfTheRing).extracting(TolkienCharacter::getName)
.contains("Boromir", "Gandalf", "Frodo", "Legolas")
.doesNotContain("Sauron", "Elrond");
// filter collection before assertion
assertThat(fellowshipOfTheRing).filteredOn("race", HOBBIT)
.containsOnly(sam, frodo, pippin, merry);
// filter collection with Java 8 Predicate
assertThat(fellowshipOfTheRing).filteredOn(character -> character.getName().contains("o"))
.containsOnly(aragorn, frodo, legolas, boromir);
// combining filtering and extraction (yes we can)
assertThat(fellowshipOfTheRing).filteredOn(character -> character.getName().contains("o"))
.containsOnly(aragorn, frodo, legolas, boromir)
.extracting(character -> character.getRace().getName())
.contains("Hobbit", "Elf", "Man");
Les objets simulacres
Différences entre mock (simulacres) et stubs (bouchons)
Bien que les concepts d'objets simulacres (mocks) et de bouchons (stubs) soient proches, on peut noter les différences suivantes :
Les bouchons (stubs) sont basés sur une vérification d'état. Ils permettent de s'abstraire d'une dépendance en fournissant des méthodes, Web
services, base de données, ayant les mêmes entrants que cette dépendance, mais en fournissant une réponse contrôlée ou prédéfinie.
Ainsi l'utilisation de bouchons permet de :
❖ tester uniquement la méthode que l'on souhaite tester sans dépendre du résultat fourni par la dépendance en question ;
❖ de développer autour de dépendances non implémentées.
Les objets simulacres (mocks), eux, sont basés sur une vérification de comportement. Contrairement aux bouchons, il ne peut s'agir que d'objets,
mais dont le comportement est également totalement contrôlé. Contrairement aux bouchons qui sont appelés de manière transparente pour
l'appelant, l'utilisation de mocks repose sur l'injection de dépendance.
Le gros avantage des mocks par rapport aux simples bouchons : permet d'être mis en place très rapidement à l'aide d'API comme Mockito au sein
même d'un testCase JUnit et permet de faire des assertions sur les appels aux méthodes du mock (vérifier qu'on appelle bien telle méthode avec
tels arguments par exemple).
Les mocks sont donc plus adaptés à l'écriture de tests unitaires ou l'on ne charge que la classe à tester en essayant de passer par tous les chemins
possibles et de faire le maximum d'assertions sur les cas de tests possibles.
Les bouchons, quant à eux, sont davantage adaptés à la mise en place de tests d'intégration où l'on charge une partie de l'environnement des
portions de code testées (par exemple : de vrais appels HTTP à des Web services bouchonnés dans le cadre d'un projet SOA).
Les objets simulacres
Les différents frameworks existants pour faire des Mocks
Voici une liste non exhaustive des frameworks permettant de mettre en place des objets simulacres en Java :
❖ Mockito
❖ EasyMock
❖ JMock
❖ PowerMock
❖ JMockit
A notre que Mockito est sans doute le plus populaire aujourd’hui. A noter également que PowerMock est essentiellement utilisé
en tant que framework complémentaire permettant de mocker des méthodes statiques (ce que ne permet pas les autres
frameworks) et propose aux choix la syntaxe EasyMock ou Mockito.
Le framework Mockito
Créer un mock
import static org.mockito.Mockito.*;
ClasseAMocker objetMock = mock(ClasseAMocker.class)
Prédire le résultat d'une méthode d’un mock
import static org.mockito.Mockito.*;
import static org.mockito.Matchers.*;
when(objetMock.methode(any(ClassArgument.class))).thenReturn(objetResultat);
when(objetMock.methode(eq(valeurArgument))).thenReturn(objetResultat);
when(objetMock.methode(valeurArgument)).thenReturn(objetResultat);
Le framework Mockito
Faire une assertion sur l’invocation d’un mock
import static org.mockito.Mockito.*;
import static org.mockito.Matchers.*;
verify(objetMock).methode(valeurArgument);
verify(objetMock).methode(eq(valeurArgument));
verify(objetMock).methode(any(ClassArgument.class));
verify(objetMock, times(0)).methode(any(ClassArgument.class)); // vérifier que la méthode n’est jamais invoquée
verify(objetMock, times(1)).methode(any(ClassArgument.class)); // vérifier que la méthode n’est invoquée qu’une fois
Les matchers
Voici une liste non exhaustive des matchers utilisés dans les instructions verify ou when :
❖ “eq” pour equals : il est implicite lorsque l’invocation du mock ne fait pas appel à d’autres matchers
❖ “any” et ses dérivés “anyString”, “anyLong”, “anyListOf(...)” : il est préconisé sur ce projet de ne pas les utiliser si vous avez la
connaissance de votre jeu de données.
Pourquoi ? Car il est préférable de maitriser son jeu de données et de ne pas faire des tests unitaires hasardeux.
Le framework Mockito
Utilisation des annotations
Il est possible d'instancier directement les objets de
Mockito tels que les mocks ou les ArgumentCaptor à l'aide
d'annotations en utilisant le runner « MockitoJUnitRunner
» de la façon suivante :
@RunWith(MockitoJUnitRunner.class)
public class MaClasseDeTest{
@Mock
ObjetMock mock;
// Dependancy injection
@InjectMocks
ControllerUsingMock controller;
@Captor
ArgumentCaptor<ArgumentAVerifier> captor;
}
Cela reviens à écrire le code suivant :
ObjetMock mock = mock(ObjetMock.class);
ArgumentCaptor<ArgumentAVerifier> captor = ArgumentCaptor.
forClass(ArgumentAVerifier.class);
ControllerUsingMock controller = new ControllerUsingMock();
controller.setObjectMock(mock);
Le framework Mockito
Les arguments captor
Ils servent à faire des assertions plus approfondies sur les paramètres passés à un objet simulacres lors d’une assertion de type
“verify”. Ces captors sont principalement utiles lorsque nous n’avons pas connaissance à l’avance de la référence de l’objet qui va
être passé en paramètre (exemple : construction d’une liste au sein de la méthode testée qui va invoquer le mock avec la
référence de cette liste). Dans le cas contraire, il est préconisé sur ce projet d’utiliser le matcher “eq” avec la référence de l’
objet.
import org.mockito.ArgumentCaptor;
import static org.mockito.Mockito.*;
import static org.mockito.Matchers.*;
ArgumentCaptor<ObjetParametreAVerifier> captor = ArgumentCaptor.forClass(ObjetParametreAVerifier.class);
verify(ObjetMock).methodeAVerifier(eq(valeur), captor.capture());
ObjetParametreAVerifier objetAVerifier = captor.getValue();
// assertions sur les méthodes de objetAVerifier
Pour créer un captor sur un paramètre de type List<?>, il faut privilégier l'utilisation des annotations :
@Captor
ArgumentCaptor<List<String>> captor;
Le framework Mockito
Les espions (spy)
Cette fois-ci, on s’écarte du principe des simulacres puisqu’il s’agit de faire des assertions sur l’invocation de méthode d’instance
réelles d’objets. En effet, Mockito permet également de faire des “verify” sur des “espions” à l’instar des mocks.
Exemple d’espion sur une liste (exemple tirée de la documentation de Mockito) :
import static org.mockito.Mockito.*;
@Test
public void whenSpyingOnList_thenCorrect() {
List<String> list = new ArrayList<String>();
List<String> spyList = spy(list);
spyList.add("one");
spyList.add("two");
verify(spyList).add("one");
verify(spyList).add("two");
assertEquals(2, spyList.size());
}
Questions
Merci, avez vous des questions ?
Sources
Voici les sources ayant servi à faire ces slides :
❖ FAQ tests en Java sur Developpez.com par Idriss Neumann : http://java.developpez.com/faq/tests/
❖ Documentation officielle AssertJ : http://joel-costigliola.github.io/assertj/
❖ Site officiel Mockito : http://mockito.org/

Más contenido relacionado

La actualidad más candente

Unit testing with NUnit
Unit testing with NUnitUnit testing with NUnit
Unit testing with NUnitkleinron
 
Formation Gratuite Total Tests par les experts Java Ippon
Formation Gratuite Total Tests par les experts Java Ippon Formation Gratuite Total Tests par les experts Java Ippon
Formation Gratuite Total Tests par les experts Java Ippon Ippon
 
Testing of React JS app
Testing of React JS appTesting of React JS app
Testing of React JS appAleks Zinevych
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
Fitnesse を用いたテストの効率化について
Fitnesse を用いたテストの効率化についてFitnesse を用いたテストの効率化について
Fitnesse を用いたテストの効率化についてtecopark
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test frameworkAbner Chih Yi Huang
 
CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~
CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~
CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~SEGADevTech
 
TDD (Test Driven Developement) et refactoring
TDD (Test Driven Developement) et refactoringTDD (Test Driven Developement) et refactoring
TDD (Test Driven Developement) et refactoringneuros
 
JAMstackは眠らない
JAMstackは眠らないJAMstackは眠らない
JAMstackは眠らないKuniyoshi Tone
 
並行計算の実践と理論
並行計算の実践と理論並行計算の実践と理論
並行計算の実践と理論gotoloop
 
Rails解説セミナー: Rails国際化 (I18n) API
Rails解説セミナー: Rails国際化 (I18n) APIRails解説セミナー: Rails国際化 (I18n) API
Rails解説セミナー: Rails国際化 (I18n) APIYohei Yasukawa
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawaクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawaShohei Okada
 
Unit tests & TDD
Unit tests & TDDUnit tests & TDD
Unit tests & TDDDror Helper
 
Test unitaire
Test unitaireTest unitaire
Test unitaireIsenDev
 
NestJS - O framework progressivo
NestJS - O framework progressivoNestJS - O framework progressivo
NestJS - O framework progressivoWender Machado
 

La actualidad más candente (20)

Unit testing with NUnit
Unit testing with NUnitUnit testing with NUnit
Unit testing with NUnit
 
Formation Gratuite Total Tests par les experts Java Ippon
Formation Gratuite Total Tests par les experts Java Ippon Formation Gratuite Total Tests par les experts Java Ippon
Formation Gratuite Total Tests par les experts Java Ippon
 
Testing of React JS app
Testing of React JS appTesting of React JS app
Testing of React JS app
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
Test unitaires
Test unitairesTest unitaires
Test unitaires
 
Fitnesse を用いたテストの効率化について
Fitnesse を用いたテストの効率化についてFitnesse を用いたテストの効率化について
Fitnesse を用いたテストの効率化について
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test framework
 
CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~
CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~
CEDEC2021 Android iOS 実機上での自動テストをより楽に有意義にする為に ~端末管理・イメージ転送・動画記録等の周辺情報のノウハウ共有~
 
TDD (Test Driven Developement) et refactoring
TDD (Test Driven Developement) et refactoringTDD (Test Driven Developement) et refactoring
TDD (Test Driven Developement) et refactoring
 
JAMstackは眠らない
JAMstackは眠らないJAMstackは眠らない
JAMstackは眠らない
 
Maven et industrialisation du logiciel
Maven et industrialisation du logicielMaven et industrialisation du logiciel
Maven et industrialisation du logiciel
 
並行計算の実践と理論
並行計算の実践と理論並行計算の実践と理論
並行計算の実践と理論
 
Spring Batch
Spring BatchSpring Batch
Spring Batch
 
Code Review
Code ReviewCode Review
Code Review
 
Rails解説セミナー: Rails国際化 (I18n) API
Rails解説セミナー: Rails国際化 (I18n) APIRails解説セミナー: Rails国際化 (I18n) API
Rails解説セミナー: Rails国際化 (I18n) API
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawaクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
 
Unit tests & TDD
Unit tests & TDDUnit tests & TDD
Unit tests & TDD
 
最速C# 7.x
最速C# 7.x最速C# 7.x
最速C# 7.x
 
Test unitaire
Test unitaireTest unitaire
Test unitaire
 
NestJS - O framework progressivo
NestJS - O framework progressivoNestJS - O framework progressivo
NestJS - O framework progressivo
 

Similar a Bbl sur les tests

testUnitaire (1).pptx
testUnitaire (1).pptxtestUnitaire (1).pptx
testUnitaire (1).pptxManalAg
 
TDD avec ou sans mock
TDD avec ou sans mockTDD avec ou sans mock
TDD avec ou sans mockYannick Ameur
 
Les cinq bonnes pratiques des Tests Unitaires dans un projet Agile
Les cinq bonnes pratiques des Tests Unitaires dans un projet AgileLes cinq bonnes pratiques des Tests Unitaires dans un projet Agile
Les cinq bonnes pratiques des Tests Unitaires dans un projet AgileDenis Voituron
 
Automatisation des tests - objectifs et concepts - partie 2
Automatisation des tests  - objectifs et concepts - partie 2Automatisation des tests  - objectifs et concepts - partie 2
Automatisation des tests - objectifs et concepts - partie 2Christophe Rochefolle
 
Avis d'expert : Les Tests Logiciels
Avis d'expert : Les Tests LogicielsAvis d'expert : Les Tests Logiciels
Avis d'expert : Les Tests LogicielsCloudNetCare
 
[PFE] Master en ingénierie du logiciel
[PFE] Master en ingénierie du logiciel[PFE] Master en ingénierie du logiciel
[PFE] Master en ingénierie du logicielUSTHB & DELTALOG
 
Industrialisation des développements logiciels
Industrialisation des développements logicielsIndustrialisation des développements logiciels
Industrialisation des développements logicielsSylvain Leroy
 
Delphi et les tests unitaires
Delphi et les tests unitairesDelphi et les tests unitaires
Delphi et les tests unitairespprem
 
13-Cours de Géniel Logiciel
13-Cours de Géniel Logiciel13-Cours de Géniel Logiciel
13-Cours de Géniel Logiciellauraty3204
 
Cocoaheads Paris Nombembre Test unitaires
Cocoaheads Paris Nombembre Test unitairesCocoaheads Paris Nombembre Test unitaires
Cocoaheads Paris Nombembre Test unitairesCocoaHeads France
 
Guide tests fonctionnels
Guide tests fonctionnelsGuide tests fonctionnels
Guide tests fonctionnelscvcby
 
RefCard Tests sur tous les fronts
RefCard Tests sur tous les frontsRefCard Tests sur tous les fronts
RefCard Tests sur tous les frontsOCTO Technology
 

Similar a Bbl sur les tests (20)

testUnitaire (1).pptx
testUnitaire (1).pptxtestUnitaire (1).pptx
testUnitaire (1).pptx
 
J Unit
J UnitJ Unit
J Unit
 
Anatomie du test
Anatomie du testAnatomie du test
Anatomie du test
 
Test logiciel
Test logicielTest logiciel
Test logiciel
 
TDD avec ou sans mock
TDD avec ou sans mockTDD avec ou sans mock
TDD avec ou sans mock
 
Flex Unit Testing
Flex Unit TestingFlex Unit Testing
Flex Unit Testing
 
Les cinq bonnes pratiques des Tests Unitaires dans un projet Agile
Les cinq bonnes pratiques des Tests Unitaires dans un projet AgileLes cinq bonnes pratiques des Tests Unitaires dans un projet Agile
Les cinq bonnes pratiques des Tests Unitaires dans un projet Agile
 
Automatisation des tests - objectifs et concepts - partie 2
Automatisation des tests  - objectifs et concepts - partie 2Automatisation des tests  - objectifs et concepts - partie 2
Automatisation des tests - objectifs et concepts - partie 2
 
Conformiq
ConformiqConformiq
Conformiq
 
Avis d'expert : Les Tests Logiciels
Avis d'expert : Les Tests LogicielsAvis d'expert : Les Tests Logiciels
Avis d'expert : Les Tests Logiciels
 
[PFE] Master en ingénierie du logiciel
[PFE] Master en ingénierie du logiciel[PFE] Master en ingénierie du logiciel
[PFE] Master en ingénierie du logiciel
 
Industrialisation des développements logiciels
Industrialisation des développements logicielsIndustrialisation des développements logiciels
Industrialisation des développements logiciels
 
Delphi et les tests unitaires
Delphi et les tests unitairesDelphi et les tests unitaires
Delphi et les tests unitaires
 
13-Cours de Géniel Logiciel
13-Cours de Géniel Logiciel13-Cours de Géniel Logiciel
13-Cours de Géniel Logiciel
 
Cocoaheads Paris Nombembre Test unitaires
Cocoaheads Paris Nombembre Test unitairesCocoaheads Paris Nombembre Test unitaires
Cocoaheads Paris Nombembre Test unitaires
 
chap6_GL.pptx
chap6_GL.pptxchap6_GL.pptx
chap6_GL.pptx
 
Les tests en PHP
Les tests en PHPLes tests en PHP
Les tests en PHP
 
Guide tests fonctionnels
Guide tests fonctionnelsGuide tests fonctionnels
Guide tests fonctionnels
 
Cours1.pptx
Cours1.pptxCours1.pptx
Cours1.pptx
 
RefCard Tests sur tous les fronts
RefCard Tests sur tous les frontsRefCard Tests sur tous les fronts
RefCard Tests sur tous les fronts
 

Más de Idriss Neumann

Suivre l'évolution du covid19 sur RaspberryPi avec la suite Elastic
Suivre l'évolution du covid19 sur RaspberryPi avec la suite ElasticSuivre l'évolution du covid19 sur RaspberryPi avec la suite Elastic
Suivre l'évolution du covid19 sur RaspberryPi avec la suite ElasticIdriss Neumann
 
Using the restful twitter’s api
Using the restful twitter’s apiUsing the restful twitter’s api
Using the restful twitter’s apiIdriss Neumann
 
Industrialisation des contrats d'interface avec netflix feign
Industrialisation des contrats d'interface avec netflix feignIndustrialisation des contrats d'interface avec netflix feign
Industrialisation des contrats d'interface avec netflix feignIdriss Neumann
 
Bbl microservices avec vert.x cdi elastic search
Bbl microservices avec vert.x cdi elastic searchBbl microservices avec vert.x cdi elastic search
Bbl microservices avec vert.x cdi elastic searchIdriss Neumann
 

Más de Idriss Neumann (6)

Suivre l'évolution du covid19 sur RaspberryPi avec la suite Elastic
Suivre l'évolution du covid19 sur RaspberryPi avec la suite ElasticSuivre l'évolution du covid19 sur RaspberryPi avec la suite Elastic
Suivre l'évolution du covid19 sur RaspberryPi avec la suite Elastic
 
Presentation uprodit
Presentation uproditPresentation uprodit
Presentation uprodit
 
Bash bonnes pratiques
Bash bonnes pratiquesBash bonnes pratiques
Bash bonnes pratiques
 
Using the restful twitter’s api
Using the restful twitter’s apiUsing the restful twitter’s api
Using the restful twitter’s api
 
Industrialisation des contrats d'interface avec netflix feign
Industrialisation des contrats d'interface avec netflix feignIndustrialisation des contrats d'interface avec netflix feign
Industrialisation des contrats d'interface avec netflix feign
 
Bbl microservices avec vert.x cdi elastic search
Bbl microservices avec vert.x cdi elastic searchBbl microservices avec vert.x cdi elastic search
Bbl microservices avec vert.x cdi elastic search
 

Bbl sur les tests

  • 1. BBL sur les tests JUnit, Mockito, AssertJ Une petite soif ? Sirotez donc un mockito (sans alcool bien sûr :p) en écoutant CE BBL! Par Idriss Neumann, le 11/02/2016
  • 2. Sommaire ❖ Généralités ➢ Pourquoi écrire des tests ? ➢ Différence entre TI et TU ➢ Démarche du TDD ❖ Le framework JUnit ➢ Définition ➢ Structure d’un test case ➢ Les différentes assertions ➢ Assertions sur exception ❖ L’alternative AssertJ ❖ Les objets simulacres ➢ Différences entre mock et stub ➢ Liste des mocking toolkits ❖ Le framework Mockito ➢ Créer un mock ➢ Prédire le résultat d’une méthode d’un mock ➢ Faire des assertions sur l’invocation d’un mock ➢ L’utilisation des annotations ➢ Les arguments captors ➢ Les espions (spy) ❖ Question
  • 3. Généralités Pourquoi écrire des tests ? Écrire des scénarios de tests automatisés (tant des tests unitaires que des tests d'intégration) constitue une étape incontournable du cycle de développement logiciel dans un cadre professionnel. Bien que cette tâche puisse parfois sembler rébarbative, elle est indispensable pour produire des développements de bonne qualité, notamment parce que cela permet entre autres de : ❖ s'assurer que l'on maîtrise les aspects fonctionnels de l'application (les besoins métier à satisfaire) ; ❖ détecter au plus tôt les anomalies éventuelles avant la livraison d'un projet aux utilisateurs ; ❖ détecter d'éventuelles régressions, suite à l'implémentation de nouvelles fonctionnalités, en automatisant l'exécution de l'ensemble de tous les scénarios de tests implémentés sous forme de tests unitaires ou tests d'intégration, de façon à ce qu'ils soient exécutés régulièrement (à minima une fois par jour par exemple). Plus l'ensemble de vos codes sera couvert par les tests, plus vous serez à même de détecter les régressions, de maîtriser l'ensemble des fonctionnalités de votre application et ainsi de la rendre plus maintenable.
  • 4. Généralités Différence entre tests unitaires et tests d’intégration De manière générale, le test unitaire a pour but de tester une partie précise d'un logiciel (d'où le nom "unitaire") voire une fonction précise, en essayant de couvrir au maximum la combinatoire des cas fonctionnels possibles sur cette portion de code. Cependant, cela ne suffit pas à différencier un test unitaire d'un test d'intégration qui, lui aussi, peut se contenter de tester une portion précise du code. La différence fondamentale est que le test unitaire doit uniquement tester le code et ne doit donc pas avoir d'interactions avec des dépendances externes du module testé telles que des bases de données, des Web services, des appels à des procédures distantes, la lecture ou écriture de fichiers ou encore d'autres fonctions. Les dépendances devront être simulées à l'aide de mécanismes tels que les bouchons ou encore les mocks. Concernant les tests d'intégration, ceux-ci permettent, de manière générale, de vérifier la bonne intégration de la portion de code testée dans l'ensemble du logiciel et de ses dépendances. Il peut s'agir tout aussi bien de vérifier la bonne insertion de données dans un SGBDR sur une petite portion de code que de scénarios complets du logiciel, correspondant à des enchaînements d'appels de fonctions, de Web services... (c'est ce que l'on appelle aussi des tests « bout en bout »).
  • 5. Généralités La démarche du TDD TDD est un acronyme pour « Test Driven Development » ou encore le développement dirigé par les tests en français. Il s'agit d'une démarche qui recommande au développeur de rédiger l'ensemble des tests unitaires avant de développer un logiciel ou les portions dont il a la charge. Cette démarche permet de s'assurer que le développeur ne sera pas influencé par son développement lors de l'écriture des cas de tests afin que ceux-ci soient davantage exhaustifs et conformes aux spécifications. Ainsi, cette démarche permet aussi de s'assurer que le développeur maîtrise les spécifications dont il a la charge avant de commencer à coder. L'approche TDD préconise le cycle court de développement en cinq étapes : 1. écrire les cas de tests d'une fonction ; 2. vérifier que les tests échouent (car le code n'existe pas encore) ; 3. développer le code fonctionnel suffisant pour valider tous les cas de tests ; 4. vérifier que les tests passent ; 5. refactoriser et optimiser en s'assurant que les tests continuent de passer.
  • 6. Le framework JUnit Qu’est-ce que JUnit JUnit est un framework Java prévu pour la réalisation de tests unitaires et d'intégration. JUnit est le framework le plus connu de la mouvance des frameworks xUnit implémentés dans de nombreuses technologies (nous pourrons également citer PHPUnit pour PHP ou encore xUnit.NET pour C# et .NET par exemple). JUnit permet de réaliser : ❖ des TestCase qui sont des classes contenant des méthodes de tests ; ❖ des TestSuite qui permettent de lancer des suites de classes de type TestCase. Voir la slide suivante pour avoir la structure globale d’une classe de test écrite en JUnit >= 4.
  • 7. Le framework JUnit import org.junit.Before; import org.junit.After; import org.junit.BeforeClass; import org.junit.AfterClass; import org.junit.Test; public class MaClasseDeTest { /** Pre et post conditions */ @BeforeClass public static void setUpBeforeClass() throws Exception { // Le contenu de cette méthode ne sera exécuté qu'une fois avant toutes les autres méthodes avec annotations // (y compris celles ayant une annotation @Before) } @AfterClass public static void tearDownClass() throws Exception { // Le contenu de cette méthode ne sera exécuté qu'une fois après toutes les autres méthodes avec annotations // (y compris celles ayant une annotation @After) } @Before public void setUp() throws Exception { // Le contenu de cette méthode sera exécuté avant chaque test (méthode avec l'annotation @Test) } @After public void tearDown() throws Exception { // Le contenu de cette méthode sera exécuté après chaque test (méthode avec l'annotation @Test) } /** Cas de tests */ @Test public void testCas1() { // Code contenant l'exécution du premier scénario avec les assertions associées } @Test public void testCas2() { // ... } }
  • 8. Le framework JUnit Les différents types d’assertions avec JUnit En informatique, une assertion est une expression qui doit être évaluée vrai ou faire échouer le programme ou le test en cas d’ échec (en levant une exception ou en mettant fin au programme par exemple). Dans le cas de JUnit et des tests d'une manière générale, on peut assimiler une assertion à une vérification et, en cas d’échec, une exception spécifique est levée (java.lang.AssertionErrorpour JUnit). Voici une liste non exhaustive des fonctions d'assertions en JUnit : ● assertEquals: vérifier l'égalité de deux expressions ; ● assertNotNull: vérifier la non-nullité d'un objet ; ● assertNull: vérifier la nullité d'un objet ; ● assertTrue: vérifier qu'une expression booléenne est vraie ; ● assertFalse: vérifier qu'une expression booléenne est fausse ; ● fail : échouer le test si cette assertion est exécutée. Ces méthodes sont surchargées pour de nombreux objets. Par exemple, la méthode assertEquals va être surchargée pour tous les types primitifs et pour les classes implémentant la méthode equals (String par exemple). Il est également possible de fournir un message d'erreur en cas d'échec d'une assertion (en premier paramètre).
  • 9. Le framework JUnit Exemples d’assertions simples Imaginons que l’on veuille tester la classe suivante : public class Addition { Integer nb1, nb2; public Addition(Integer nb1, Integer nb2){ this.nb1 = nb1; this.nb2 = nb2; } public Integer somme(){ return nb1 + nb2; } public Integer getNb1() { return nb1; } public Integer getNb2() { return nb2; } } Voici un exemple de fonction de test : @Test public void testCasAdditionNominal() { Addition add = new Addition(1, 2); // vérification, on a bien valorisé l'attribut nb1 assertEquals(1, add.getNb1()); // vérification, on a bien valorisé l'attribut nb2 assertEquals(2, add.getNb2()); // vérification sur la méthode somme() assertEquals("Erreur dans le calcul de la somme", 3, add.somme()); } Remarque : les imports statiques sont préconisés pour les méthodes statiques provenant des frameworks de tests présentés dans ce BBL.
  • 10. Le framework JUnit Exemples d’assertions sur des exceptions Il est possible de vérifier la levée d'une exception grâce à l'annotation @Test(expected=<nom>.class) : // Ce test va réussir @Test(expected = java.lang.NullPointerException.class) public final void testException(){ Long variablePasInstanciee = null; variablePasInstanciee.toString(); } // Ce test va échouer @Test(expected = java.lang.NullPointerException.class) public final void testException2(){ Long variableInstanciee = 1L; variableInstanciee.toString(); }
  • 11. L’alternative AssertJ Une alternative aux assertions JUnit sont les assertions d’AssertJ, une librairie mettant à disposition des assertions tout en adoptant le “fluent code style”. Il s’agit de la syntaxe préconisée sur le projet Hub numérique. Voici des exemples d’assertions issues de la documentation officielle d’AssertJ: // unique entry point to get access to all assertThat methods and utility methods (e.g. entry) import static org.assertj.core.api.Assertions.*; // basic assertions assertThat(frodo.getName()).isEqualTo("Frodo"); assertThat(frodo).isNotEqualTo(sauron) .isIn(fellowshipOfTheRing); // String specific assertions assertThat(frodo.getName()).startsWith("Fro") .endsWith("do") .isEqualToIgnoringCase("frodo"); // collection specific assertions assertThat(fellowshipOfTheRing).hasSize(9) .contains(frodo, sam) .doesNotContain(sauron);
  • 12. L’alternative AssertJ // using extracting magical feature to check fellowshipOfTheRing characters name :) assertThat(fellowshipOfTheRing).extracting("name") .contains("Boromir", "Gandalf", "Frodo", "Legolas") .doesNotContain("Sauron", "Elrond"); // Extracting with Java 8 love (type safe) assertThat(fellowshipOfTheRing).extracting(TolkienCharacter::getName) .contains("Boromir", "Gandalf", "Frodo", "Legolas") .doesNotContain("Sauron", "Elrond"); // filter collection before assertion assertThat(fellowshipOfTheRing).filteredOn("race", HOBBIT) .containsOnly(sam, frodo, pippin, merry); // filter collection with Java 8 Predicate assertThat(fellowshipOfTheRing).filteredOn(character -> character.getName().contains("o")) .containsOnly(aragorn, frodo, legolas, boromir); // combining filtering and extraction (yes we can) assertThat(fellowshipOfTheRing).filteredOn(character -> character.getName().contains("o")) .containsOnly(aragorn, frodo, legolas, boromir) .extracting(character -> character.getRace().getName()) .contains("Hobbit", "Elf", "Man");
  • 13. Les objets simulacres Différences entre mock (simulacres) et stubs (bouchons) Bien que les concepts d'objets simulacres (mocks) et de bouchons (stubs) soient proches, on peut noter les différences suivantes : Les bouchons (stubs) sont basés sur une vérification d'état. Ils permettent de s'abstraire d'une dépendance en fournissant des méthodes, Web services, base de données, ayant les mêmes entrants que cette dépendance, mais en fournissant une réponse contrôlée ou prédéfinie. Ainsi l'utilisation de bouchons permet de : ❖ tester uniquement la méthode que l'on souhaite tester sans dépendre du résultat fourni par la dépendance en question ; ❖ de développer autour de dépendances non implémentées. Les objets simulacres (mocks), eux, sont basés sur une vérification de comportement. Contrairement aux bouchons, il ne peut s'agir que d'objets, mais dont le comportement est également totalement contrôlé. Contrairement aux bouchons qui sont appelés de manière transparente pour l'appelant, l'utilisation de mocks repose sur l'injection de dépendance. Le gros avantage des mocks par rapport aux simples bouchons : permet d'être mis en place très rapidement à l'aide d'API comme Mockito au sein même d'un testCase JUnit et permet de faire des assertions sur les appels aux méthodes du mock (vérifier qu'on appelle bien telle méthode avec tels arguments par exemple). Les mocks sont donc plus adaptés à l'écriture de tests unitaires ou l'on ne charge que la classe à tester en essayant de passer par tous les chemins possibles et de faire le maximum d'assertions sur les cas de tests possibles. Les bouchons, quant à eux, sont davantage adaptés à la mise en place de tests d'intégration où l'on charge une partie de l'environnement des portions de code testées (par exemple : de vrais appels HTTP à des Web services bouchonnés dans le cadre d'un projet SOA).
  • 14. Les objets simulacres Les différents frameworks existants pour faire des Mocks Voici une liste non exhaustive des frameworks permettant de mettre en place des objets simulacres en Java : ❖ Mockito ❖ EasyMock ❖ JMock ❖ PowerMock ❖ JMockit A notre que Mockito est sans doute le plus populaire aujourd’hui. A noter également que PowerMock est essentiellement utilisé en tant que framework complémentaire permettant de mocker des méthodes statiques (ce que ne permet pas les autres frameworks) et propose aux choix la syntaxe EasyMock ou Mockito.
  • 15. Le framework Mockito Créer un mock import static org.mockito.Mockito.*; ClasseAMocker objetMock = mock(ClasseAMocker.class) Prédire le résultat d'une méthode d’un mock import static org.mockito.Mockito.*; import static org.mockito.Matchers.*; when(objetMock.methode(any(ClassArgument.class))).thenReturn(objetResultat); when(objetMock.methode(eq(valeurArgument))).thenReturn(objetResultat); when(objetMock.methode(valeurArgument)).thenReturn(objetResultat);
  • 16. Le framework Mockito Faire une assertion sur l’invocation d’un mock import static org.mockito.Mockito.*; import static org.mockito.Matchers.*; verify(objetMock).methode(valeurArgument); verify(objetMock).methode(eq(valeurArgument)); verify(objetMock).methode(any(ClassArgument.class)); verify(objetMock, times(0)).methode(any(ClassArgument.class)); // vérifier que la méthode n’est jamais invoquée verify(objetMock, times(1)).methode(any(ClassArgument.class)); // vérifier que la méthode n’est invoquée qu’une fois Les matchers Voici une liste non exhaustive des matchers utilisés dans les instructions verify ou when : ❖ “eq” pour equals : il est implicite lorsque l’invocation du mock ne fait pas appel à d’autres matchers ❖ “any” et ses dérivés “anyString”, “anyLong”, “anyListOf(...)” : il est préconisé sur ce projet de ne pas les utiliser si vous avez la connaissance de votre jeu de données. Pourquoi ? Car il est préférable de maitriser son jeu de données et de ne pas faire des tests unitaires hasardeux.
  • 17. Le framework Mockito Utilisation des annotations Il est possible d'instancier directement les objets de Mockito tels que les mocks ou les ArgumentCaptor à l'aide d'annotations en utilisant le runner « MockitoJUnitRunner » de la façon suivante : @RunWith(MockitoJUnitRunner.class) public class MaClasseDeTest{ @Mock ObjetMock mock; // Dependancy injection @InjectMocks ControllerUsingMock controller; @Captor ArgumentCaptor<ArgumentAVerifier> captor; } Cela reviens à écrire le code suivant : ObjetMock mock = mock(ObjetMock.class); ArgumentCaptor<ArgumentAVerifier> captor = ArgumentCaptor. forClass(ArgumentAVerifier.class); ControllerUsingMock controller = new ControllerUsingMock(); controller.setObjectMock(mock);
  • 18. Le framework Mockito Les arguments captor Ils servent à faire des assertions plus approfondies sur les paramètres passés à un objet simulacres lors d’une assertion de type “verify”. Ces captors sont principalement utiles lorsque nous n’avons pas connaissance à l’avance de la référence de l’objet qui va être passé en paramètre (exemple : construction d’une liste au sein de la méthode testée qui va invoquer le mock avec la référence de cette liste). Dans le cas contraire, il est préconisé sur ce projet d’utiliser le matcher “eq” avec la référence de l’ objet. import org.mockito.ArgumentCaptor; import static org.mockito.Mockito.*; import static org.mockito.Matchers.*; ArgumentCaptor<ObjetParametreAVerifier> captor = ArgumentCaptor.forClass(ObjetParametreAVerifier.class); verify(ObjetMock).methodeAVerifier(eq(valeur), captor.capture()); ObjetParametreAVerifier objetAVerifier = captor.getValue(); // assertions sur les méthodes de objetAVerifier Pour créer un captor sur un paramètre de type List<?>, il faut privilégier l'utilisation des annotations : @Captor ArgumentCaptor<List<String>> captor;
  • 19. Le framework Mockito Les espions (spy) Cette fois-ci, on s’écarte du principe des simulacres puisqu’il s’agit de faire des assertions sur l’invocation de méthode d’instance réelles d’objets. En effet, Mockito permet également de faire des “verify” sur des “espions” à l’instar des mocks. Exemple d’espion sur une liste (exemple tirée de la documentation de Mockito) : import static org.mockito.Mockito.*; @Test public void whenSpyingOnList_thenCorrect() { List<String> list = new ArrayList<String>(); List<String> spyList = spy(list); spyList.add("one"); spyList.add("two"); verify(spyList).add("one"); verify(spyList).add("two"); assertEquals(2, spyList.size()); }
  • 20. Questions Merci, avez vous des questions ?
  • 21. Sources Voici les sources ayant servi à faire ces slides : ❖ FAQ tests en Java sur Developpez.com par Idriss Neumann : http://java.developpez.com/faq/tests/ ❖ Documentation officielle AssertJ : http://joel-costigliola.github.io/assertj/ ❖ Site officiel Mockito : http://mockito.org/