JUnit, un framework de test unitaire pour Java

publicité
JUnit, un framework de test unitaire pour Java
JUnit, un framework de test unitaire pour Java
Clémentine Nebut
LIRMM / Université de Montpellier
26 Septembre 2016
JUnit, un framework de test unitaire pour Java
Introduction
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Introduction
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Introduction
JUNit
Origine
Xtreme programming (test-rst development), méthodes agiles
framework de test écrit en Java par E. Gamma et K. Beck
open source : www.junit.org
Objectifs
test d'applications en Java
faciliter la création des tests
tests de non régression
JUnit, un framework de test unitaire pour Java
Introduction
Ce que fait JUnit
Enchaîne l'exécution des méthodes de test dénies par le
testeur
Facilite la dénition des tests grâce à des assertions, des
méthodes d'initialisation et de nalisation
Permet en un seul clic de savoir quels tests ont
échoué/planté/réussi
JUnit (et au delà xUnit) est de facto devenu un standard en
matière de test
JUnit, un framework de test unitaire pour Java
Introduction
Ce que ne fait pas JUnit
JUnit n'écrit pas les tests !
Il ne fait que les lancer.
JUnit ne propose pas de principes/méthodes pour structurer
les tests
JUnit, un framework de test unitaire pour Java
Introduction
JUnit : un framework
Le framework dénit toute l'infrastructure nécessaire pour :
écrire des tests
dénir leurs oracles
lancer les tests
Utiliser Junit :
dénir les tests
s'en remettre à JUnit pour leur exécution
ne pas appeler explicitement les méthodes de test
JUnit, un framework de test unitaire pour Java
Introduction
JUnit : versions initiales et versions ≥4
Versions initiales
Paramétrage par spécialisation
Utilisation de conventions de nommage
Versions ≥4
Utilisation d'annotations
beaucoup de nouvelles fonctionalités dans JUnit 4
attention, la plupart des docs trouvées sur internet se basent
sur junit 3
pas de runner graphique en version 4, laissé au soin des IDEs
JUnit, un framework de test unitaire pour Java
Les bases
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Les bases
Écriture de test : principe général
On crée une ou plusieurs classes destinées à contenir les tests :
les classes de test.
On y insère des méthodes de test.
Une méthode de test
fait appel à une ou plusieurs méthodes du système à tester,
ce qui suppose d'avoir une instance d'une classe du système à
tester (la création d'une telle instance peut être placée à
plusieurs endroits, voir plus loin),
inclut des instructions permettant un verdict automatique : les
assertions.
JUnit, un framework de test unitaire pour Java
Les bases
Classe de test
Contient les méthodes de test
Est une collection de cas de test (sans ordre)
peut contenir des méthodes particulières pour positionner
l'environnement de test
En JUnit :
Junit versions <4 : la classe de test hérite de
JUnit.framework.TestCase
JUnit versions ≥4 : une classe quelconque
JUnit, un framework de test unitaire pour Java
Les bases
Cas de test / méthode de test
s'intéresse à une seule unité de code/ un seul comportement
doit rester court
les cas de test sont indépendants les uns des autres
Avec Junit, un cas de test ≡ une méthode (méthode de test)
Junit versions <4 : les méthodes de test commencent par le
mot test
JUnit versions ≥4 : annotées @Test
les méthodes de test seront appelées par Junit, dans un ordre
supposé quelconque.
JUnit, un framework de test unitaire pour Java
Les bases
Les méthodes de test
sont sans paramètres et sans type de retour (logique
puisqu'elles vont être appelées automatiquement par JUnit)
embarquent l'oracle
i.e. contiennent des assertions
x vaut 3
le résultat de l'appel de telle méthode est non nul
x est plus petit que y
JUnit, un framework de test unitaire pour Java
Les bases
Les verdicts
Sont dénis grâce aux assertions placées dans les cas de test.
Pass (vert) : pas de faute détectée
Fail (rouge) : échec, on attendait un résultat, on en a eu un
autre
Error : le test n'a pas pû s'exécuter correctement (exception
inattendue, ...)
En JUnit 4, plus de diérence entre fail et error
JUnit, un framework de test unitaire pour Java
Les bases
Exemple en version 4 classe à tester
http ://code.google.com/p/t2framework/wiki/JUnitQuickTutorial
public class Subscription {
p r i v a t e i n t p r i c e ; // s u b s c r i p t i o n t o t a l p r i c e i n euro −c e n t
p r i v a t e i n t l e n g t h ; // l e n g t h o f s u b s c r i p t i o n i n months
// c o n s t r u c t o r :
public Subscription ( int p , int n) {
price = p ;
length = n ;
}
/ ∗∗
∗ C a l c u l a t e the monthly s u b s c r i p t i o n
∗ r o u n d e d up t o t h e n e a r e s t c e n t .
∗/
p r i c e i n euro ,
p u b l i c double pricePerMonth () {
double r = ( double ) p r i c e / ( double ) length ;
return r ;
}
/ ∗∗
∗ Call
∗/
t h i s to c a n c e l / n u l i f y t h i s s u b s c r i p t i o n .
public void cancel () { length = 0 ; }
}
JUnit, un framework de test unitaire pour Java
Les bases
Exemple en version 4 objectif de test
http ://code.google.com/p/t2framework/wiki/JUnitQuickTutorial
If we have a subscription of 200 cent for a period of 2 month,
its monthly price should be 1 euro, right ?
The monthly price is supposed to be rounded up to the nearest
cent. So, if we have a subscription of 200 cent for a period of
3 month, its monthly price should be 0.67 euro.
JUnit, un framework de test unitaire pour Java
Les bases
Exemple en version 4 classe de test
http ://code.google.com/p/t2framework/wiki/JUnitQuickTutorial
import org . j u n i t .∗ ;
import s t a t i c org . j u n i t . Assert .∗ ;
public class SubscriptionTest {
@Test
public void test_returnEuro () {
System . o u t . p r i n t l n ( " T e s t i f p r i c e P e r M o n t h r e t u r n s Euro . . . " ) ;
S u b s c r i p t i o n S = new S u b s c r i p t i o n ( 2 0 0 , 2 ) ;
a s s e r t T r u e ( S . p r i c e P e r M o n t h ( ) == 1 . 0 ) ;
}
}
@Test
p u b l i c v o i d test_roundUp ( ) {
System . o u t . p r i n t l n ( " T e s t i f p r i c e P e r M o n t h r o u n d s up c o r r e c t l y . . . " ) ;
S u b s c r i p t i o n S = new S u b s c r i p t i o n ( 2 0 0 , 3 ) ;
a s s e r t T r u e ( S . p r i c e P e r M o n t h ( ) == 0 . 6 7 ) ;
}
JUnit, un framework de test unitaire pour Java
Les bases
L'environnement de test
Les méthodes de test ont besoin d'être appelées sur des
instances
Déclaration et création des instances
en général, les instances sont déclarées comme membres
d'instance de la classe de test
la création des instances et plus globalement la mise en place
de l'environnement de test est laissé à la charge de méthodes
d'initialisation
NB : ce n'est pas ce qui a été fait dans l'exemple précédent.
JUnit, un framework de test unitaire pour Java
Les bases
Préambules et postambules
Méthodes écrites par le testeur pour mettre en place
l'environnement de test.
JUnit 4 : Méthodes avec annotations @Before et @After ; JUnit
3 : Méthodes appelées setUp et tearDown
exécutées avant/après chaque méthode de test (l'exécution est
pilotée par le framework, et pas le testeur)
possibilité d'annoter plusieurs méthodes (ordre d'exécution
indéterminé)
publiques et non statiques
Méthodes avec annotations @BeforeClass et @AfterClass (pas
en JUnit 3)
exécutées avant (resp. après) la première (resp. dernière)
méthode de test
une seule méthode pour chaque annotation
publiques et statiques
JUnit, un framework de test unitaire pour Java
Approfondissements
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Approfondissements
Détails sur les méthodes de test en JUnit ≥ 4
L'annotation @Test peut prendre en paramètre :
le type d'exception attendue
@Test(expected=monexception.class) Succès ssi cette
exception est lancée.
un timeout : @Test (timeout=10) (en ms). Fail si la réponse
n'arrive pas avant le timeout.
annotation @ignore (paramètre optionnel : du texte) pour
ignorer le test
JUnit, un framework de test unitaire pour Java
Approfondissements
Les asssertions
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Approfondissements
Les asssertions
Les assertions (en JUnit 4)
Permettent d'embarquer et d'automatiser l'oracle dans les cas
de test (adieu, println ...)
Utilisation de org.junit.Assert.*
attention, import statique, car les asserts sont des méthodes
statiques
import static org.junit.Assert.* ;
Lancent des exceptions de type java.lang.AssertionError
(comme les assert java classiques)
Diérentes assertions : comparaison à un delta près,
comparaison de tableaux (arrays), ...
Forte surcharge des méthodes d'assertion.
JUnit, un framework de test unitaire pour Java
Approfondissements
Les asssertions
Assert that (nouveauté version 4.4)
assertThat([value], [matcher statement]);
exemples :
assertThat(x, is(3)) ;
assertThat(x, is(not(4))) ;
assertThat(responseString,
either(containsString("color")).or(containsString("colour"))) ;
assertThat(myList, hasItem("3")) ;
not(s), either(s).or(ss), each(s)
Messages d'erreur plus clairs
http ://junit.sourceforge.net/doc/ReleaseNotes4.4.html
JUnit, un framework de test unitaire pour Java
Approfondissements
Les asssertions
Assumptions (nouveauté version 4.4)
AssumeThat(File.separatorChar, is(/))
L'assertion suivante sera ignorée si la supposition n'est pas
vériée
JUnit, un framework de test unitaire pour Java
Approfondissements
Le test paramétré
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Approfondissements
Le test paramétré
Test paramétré
Objectif : réutiliser une méthode de test avec des jeux de
données de test diérents
Jeux de données de test
retournés par une méthode annotée @Parameters
cette méthode retourne une collection de tableaux contenant
les données et éventuellement le résultat attendu
La classe de test
annotée @RunWith(Parameterized.class)
contient des méthodes devant être exécutées avec chacun des
jeux de données
Pour chaque donnée, la classe est instanciée, les méthodes de
test sont exécutées
JUnit, un framework de test unitaire pour Java
Approfondissements
Le test paramétré
Test paramétré : les besoins
Un constructeur public qui utilise les paramètres (i.e. un jeu de
données quelconque)
La méthode qui retourne les paramètres (i.e. les jeux de
données) doit être statique
JUnit, un framework de test unitaire pour Java
Approfondissements
Le test paramétré
Exemple de test paramétré : test de Sum :int sum(int x, int
y)
import org . j u n i t . Test ;
i m p o r t o r g . j u n i t . r u n n e r . RunWith ;
import org . j u n i t . runners . Parameterized ;
import org . j u n i t . runners . Parameterized . Parameters ;
import s t a t i c org . j u n i t . Assert . ∗ ;
import java . u t i l . ∗ ;
@RunWith ( P a r a m e t e r i z e d . c l a s s )
p u b l i c c l a s s TestParamSum {
private int x ;
private int y ;
private int res ;
p u b l i c TestParamSum ( i n t x , i n t y , i n t r e s ) {
this .x = x;
this .y = y;
this . res = res ;}
@Parameters
public s t a t i c Collection testData () {
r e t u r n A r r a y s . a s L i s t ( new O b j e c t [ ] [ ] {
{ 0 , 0 , 0 } ,{ 1 , 1 , 2 } ,{ 2 , 1 , 3 } ,{10 , 9 , 19}});}
@ T e s t p u b l i c v o i d testSum ( ) {
a s s e r t E q u a l s ( r e s , new Sum ( ) . sum ( x , y ) ) ;
}
}
JUnit, un framework de test unitaire pour Java
Approfondissements
Les suites de test
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Approfondissements
Les suites de test
Suite de tests
Rassemble des cas de test pour enchaîner leur exécution
i.e. groupe l'exécution de classes de test
i m p o r t o r g . j u n i t . r u n n e r . RunWith ;
import org . j u n i t . runners . Suite ;
@RunWith ( S u i t e . c l a s s )
@Suite . S u i t e C l a s s e s ({
ClasseDeTest1 . class ,
ClasseDeTest2 . c l a s s
})
p u b l i c c l a s s MaSuiteDeTest {
}
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
Classe à tester
package c a l c ;
public class Calculator {
p r i v a t e s t a t i c i n t r e s u l t ; / / S t a t i c v a r i a b l e where t h e r e s u l t i s s t o r e d
p u b l i c v o i d add ( i n t n ) {
result = result + n;
}
public void substract ( int n) {
r e s u l t = r e s u l t − 1;
//Bug : s h o u l d be r e s u l t = r e s u l t − n
}
p u b l i c v o i d m u l t i p l y ( i n t n ) {}
// Not i m p l e m e n t e d y e t
public void divide ( int n) {
result = result / n;
}
public void square ( i n t n) {
result = n ∗ n;
}
p u b l i c void squareRoot ( i n t n) {
for (; ;) ;
//Bug : l o o p s i n d e f i n i t e l y
}
public void clear () {
// C l e a n s t h e r e s u l t
r e s u l t = 0;
}
p u b l i c v o i d s w i t c h O n ( ) {// S w i t h on t h e s c r e e n , d i s p l a y " h e l l o " , beep
r e s u l t = 0;
// and do o t h e r t h i n g s t h a t c a l c u l a t o r do nowadays
}
p u b l i c v o i d s w i t c h O f f ( ) { }// D i s p l a y " bye bye " , beep , s w i t c h o f f t h e s c r e e n
public int getResult () {
return result ;
}
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
Une classe de test
import c a l c . C a l c u l a t o r ;
import org . j u n i t . Before ;
import org . j u n i t . Ignore ;
import org . j u n i t . Test ;
import s t a t i c org . j u n i t . Assert . ∗ ;
public class CalculatorTest {
p r i v a t e s t a t i c C a l c u l a t o r c a l c u l a t o r = new C a l c u l a t o r ( ) ;
@Before
public void clearCalculator () {
calculator . clear ();
}
@Test
p u b l i c v o i d add ( ) {
c a l c u l a t o r . add ( 1 ) ;
c a l c u l a t o r . add ( 1 ) ;
assertEquals ( calculator . getResult () , 2);
}
@Test
public void subtract () {
c a l c u l a t o r . add ( 1 0 ) ;
calculator . subtract (2);
assertEquals ( calculator . getResult () , 8);
}
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
suite
}
@Test
public void divide () {
c a l c u l a t o r . add ( 8 ) ;
calculator . divide (2);
a s s e r t c a l c u l a t o r . g e t R e s u l t ( ) == 5 ;
}
@Test ( e x p e c t e d = A r i t h m e t i c E x c e p t i o n . c l a s s )
public void divideByZero () {
calculator . divide (0);
}
@Ignore (" not ready yet ")
@Test
public void multiply () {
c a l c u l a t o r . add ( 1 0 ) ;
calculator . multiply (10);
assertEquals ( calculator . getResult () , 100);
}
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
Une autre classe de test
import c a l c . C a l c u l a t o r ;
import org . j u n i t . A f t e r C l a s s ;
import org . j u n i t . Before ;
import org . j u n i t . BeforeClass ;
import org . j u n i t . Test ;
import s t a t i c org . j u n i t . Assert . ∗ ;
p u b l i c c l a s s AdvancedTest e x t e n d s A b s t r a c t P a r e n t {
private static Calculator calculator ;
@BeforeClass
public s t a t i c void switchOnCalculator () {
System . o u t . p r i n t l n ( " S w i t c h on c a l c u l a t o r " ) ;
c a l c u l a t o r = new C a l c u l a t o r ( ) ;
c a l c u l a t o r . switchOn ( ) ;
}
@AfterClass
public s t a t i c void switchOffCalculator () {
System . o u t . p r i n t l n ( " S w i t c h o f f c a l c u l a t o r " ) ;
calculator . switchOff ( ) ;
calculator = null ;
}
@Before
public void clearCalculator () {
System . o u t . p r i n t l n ( " C l e a r c a l c u l a t o r " ) ;
calculator . clear ();
}
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
suite
@Test ( t i m e o u t = 1 0 0 0 )
p u b l i c void squareRoot () {
c a l c u l a t o r . squareRoot ( 2 ) ;
}
@Test
public void square2 () {
c a l c u l a t o r . square (2);
assertEquals (4 , c a l c u l a t o r . getResult ( ) ) ;
}
@Test
public void square4 () {
c a l c u l a t o r . square (4);
a s s e r t E q u a l s (16 , c a l c u l a t o r . getResult ( ) ) ;
}
@Test
public void square5 () {
c a l c u l a t o r . square (5);
a s s e r t E q u a l s (25 , c a l c u l a t o r . getResult ( ) ) ;
}
}
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
suite
package j u n i t 4 ;
import org . j u n i t . ∗ ;
public abstract c la s s AbstractParent {
@BeforeClass
public s t a t i c void startTestSystem () {
System . o u t . p r i n t l n ( " S t a r t t e s t s y s t e m " ) ;
}
@AfterClass
p u b l i c s t a t i c void stopTestSystem () {
System . o u t . p r i n t l n ( " Stop t e s t s y s t e m " ) ;
}
@Before
public void initTestSystem () {
System . o u t . p r i n t l n ( " I n i t i a l i z e t e s t s y s t e m " ) ;
}
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
Avec tests paramétrés
import c a l c . C a l c u l a t o r ;
import s t a t i c org . j u n i t . Assert . a s s e r t E q u a l s ;
import org . j u n i t . Test ;
i m p o r t o r g . j u n i t . r u n n e r . RunWith ;
import org . j u n i t . runners . Parameterized ;
import org . j u n i t . runners . Parameterized . Parameters ;
import java . u t i l . Arrays ;
import java . u t i l . C o l l e c t i o n ;
@RunWith ( P a r a m e t e r i z e d . c l a s s )
p u b l i c c l a s s SquareTest {
p r i v a t e s t a t i c C a l c u l a t o r c a l c u l a t o r = new C a l c u l a t o r ( ) ;
p r i v a t e i n t param ;
private int result ;
@Parameters
p u b l i c s t a t i c C o l l e c t i o n data () {
r e t u r n A r r a y s . a s L i s t ( new O b j e c t [ ] [ ] {
{0 , 0} , {1 , 1} ,
{2 , 4} , {4 , 16} ,
{ 5 , 2 5 } , { 6 , 3 6 } , { 7 , 49}
});
}
p u b l i c S q u a r e T e s t ( i n t param , i n t r e s u l t ) {
t h i s . param = param ;
this . result = result ;
}
@Test
public void square () {
c a l c u l a t o r . s q u a r e ( param ) ;
assertEquals ( result , calculator . getResult ());
JUnit, un framework de test unitaire pour Java
Approfondissements
Autre exemple
Une Suite de tests qui regroupe les 2 classes de test
i m p o r t o r g . j u n i t . r u n n e r . RunWith ;
import org . j u n i t . runners . Suite ;
@RunWith ( S u i t e . c l a s s )
@Suite . S u i t e C l a s s e s ({
CalculatorTest . class ,
SquareTest . c l a s s
})
public class AllCalculatorTests {
}
JUnit, un framework de test unitaire pour Java
JUnit et introspection
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
JUnit et introspection
JUnit : un framework
Extraits de code de collecte des méthodes de test, JUnit 3
p u b l i c T e s t S u i t e ( f i n a l C l a s s t h e C l a s s ){
...
Method [ ] = t h e C l a s s . g e t D e c l a r e d M e t h o d s
...
}
p r i v a t e b o o l e a n i s T e s t M e t h o d ( Method m) {
S t r i n g name= m. getName ( ) ;
C l a s s [ ] p a r a m e t e r s= m. g e t P a r a m e t e r T y p e s ( ) ;
C l a s s r e t u r n T y p e= m. g e t R e t u r n T y p e ( ) ;
r e t u r n p a r a m e t e r s . l e n g t h == 0 && name . s t a r t s W i t h ( " t e s t " )
&& r e t u r n T y p e . e q u a l s ( Void . TYPE ) ;
}
JUnit, un framework de test unitaire pour Java
JUnit et introspection
JUnit : un framework
Extraits de code de collecte des méthodes de test, JUnit 3
Dans BlockJUnit4ClassRunner
p r o t e c t e d L i s t <FrameworkMethod> computeTestMethods ( ) {
r e t u r n g e t T e s t C l a s s ( ) . getAnnotatedMethods ( Test . c l a s s ) ;
}
Dans TestClass.java
p u b l i c L i s t <FrameworkMethod> g e t A n n o t a t e d M e t h o d s (
C l a s s <? e x t e n d s A n n o t a t i o n > a n n o t a t i o n C l a s s ) {
r e t u r n getAnnotatedMembers ( f M e t h o d s F o r A n n o t a t i o n s , a n n o t a t i o n C l a s s ) ;
}
JUnit, un framework de test unitaire pour Java
Conclusion
Sommaire
1 Introduction
2 Les bases
3 Approfondissements
Les asssertions
Le test paramétré
Les suites de test
Autre exemple issu de
http ://www.devx.com/Java/Article/31983
4 JUnit et introspection
5 Conclusion
JUnit, un framework de test unitaire pour Java
Conclusion
Conclusion sur JUnit
Construction rapide de tests
Exécution rapide
Très bien adapté pour le test unitaire et test de non régression
JUnit, un framework de test unitaire pour Java
Conclusion
JUnit et les autres
NUnit -> .net
PiUnit -> python
FlexUnit -> Flex
etc ...
Téléchargement