25
EX4C Systèmes d’exploitation Tests unitaires Utilisation de la librairie CUnit Sébastien Combéfis mardi 3 mars 2015

Tests unitaires : Utilisation de la librairie CUnit

Embed Size (px)

Citation preview

Page 1: Tests unitaires : Utilisation de la librairie CUnit

EX4C Systèmes d’exploitation

Tests unitaires

Utilisation dela librairie CUnit

Sébastien Combéfis mardi 3 mars 2015

Page 2: Tests unitaires : Utilisation de la librairie CUnit

Ce(tte) œuvre est mise à disposition selon les termes de la Licence Creative CommonsAttribution – Pas d’Utilisation Commerciale – Pas de Modification 4.0 International.

Page 3: Tests unitaires : Utilisation de la librairie CUnit

Test unitaire

Test indépendant d’unités de code

Une classe, un module, une procédure/fonction...

Un test par unité, sans dépendre des autres

En les supposant correctes ou en définissant des stubs, mocks...

Plusieurs objectifsTrouver rapidement des erreurs

Sécuriser la maintenance

Documenter le code

Utilisés en TDD, et en Extreme Programming (XP)

3

Page 4: Tests unitaires : Utilisation de la librairie CUnit

TDD

Test Driven Development (TDD)

Pilotage du développement par les tests

Tests construits sur base des spécifications des unités de code

Tests fonctionnels en mode black-box

Définition des objectifs clairs avant même l’implémentation

Diminue le risque d’erreurs de conception dues à la précipitation

Augmente la confiance en soi du programmeur

Assurance qu’une réfactorisation préserve les fonctionnalités

4

Page 5: Tests unitaires : Utilisation de la librairie CUnit

Quelques principes

KISS, “Keep It Simple, Stupid”

Restez simple, ne foncez pas dans la complexité, up to the point

YAGNI, “You Aren’t Gonna Need It”

Ne pas ajouter des fonctionnalités tant que ce n’est pas nécessaire

RERO, “Release Early, Release Often”

Rétroactions développeur/testeur par courtes phases de release

5

Page 6: Tests unitaires : Utilisation de la librairie CUnit

Cycle TDD

1 Écrire un premier test

2 Vérifier qu’il échoue

L’implémentation n’étant pas fournie, il doit échouer

3 Écrire l’implémentation pour passer le test

4 Vérifier que le test passe

5 Réfactoriser le code

Améliorer sa qualité tout en gardant les mêmes fonctionnalités

6

Page 7: Tests unitaires : Utilisation de la librairie CUnit

Structure d’un test

1 Initialisation (setup)

Initialiser l’unité de code testée et son environnement

2 Exécution

Exécuter l’unité de code testée, et récupérer ses résultats

3 Validation

Vérifier que les résultats produits sont ceux attendus

4 Nettoyage (cleanup)

Restaurer l’état de l’unité de code testée et de l’environnement

7

Page 8: Tests unitaires : Utilisation de la librairie CUnit

Bonnes pratiques

Séparer les initialisations communes des spécifiques

Focus de la validation sur l’unité de code testée

Mêmes exigences pour les tests que le code de production

Code de qualité, gestion des cas positifs et négatifs, maintenable

Produire les tests avant l’implémentation

Forcer une définition claire des spécifications

8

Page 9: Tests unitaires : Utilisation de la librairie CUnit

Librairie CUnit

Librairie légère pour écrire et exécuter des tests unitaires en C

Propose plusieurs interfaces utilisateurs flexibles

Librairie statique liée avec le code de test

Framework pour structurer les tests et ensemble d’assertions

Plusieurs interfaces d’exécution des testsNon-interactive (résultat en XML)

Interactive en console (ANSI C) ou graphique (curses)

http://cunit.sourceforge.net/

9

Page 10: Tests unitaires : Utilisation de la librairie CUnit

Exemple 1 : Factorielle

Spécifications précises de la fonction factorielle

Bien identifier la valeur de retour et les cas particuliers

1 // Computes the f a c t o r i a l o f an i n t e g e r2 //3 // Retu rns the f a c t o r i a l o f n4 // or −1 i f n < 05 i n t f a c t o r i a l ( i n t n ) ;

10

Page 11: Tests unitaires : Utilisation de la librairie CUnit

Procédure de test

Tester différents cas possibles et penser aux cas limites

1 #i n c l u d e " f a c t o r i a l . h"2 #i n c l u d e " CUnit / Bas i c . h"34 vo id t e s t _ f a c t o r i a l ( vo id )5 {6 CU_ASSERT ( f a c t o r i a l (−15) == −1);7 CU_ASSERT ( f a c t o r i a l (−1) == −1);89 CU_ASSERT ( f a c t o r i a l ( 0 ) == 1 ) ;

1011 CU_ASSERT ( f a c t o r i a l ( 1 ) == 1 ) ;12 CU_ASSERT ( f a c t o r i a l ( 2 ) == 2 ) ;13 CU_ASSERT ( f a c t o r i a l ( 6 ) == 7 2 0 ) ;14 }

11

Page 12: Tests unitaires : Utilisation de la librairie CUnit

Implémentation de la fonction

1 #i n c l u d e " f a c t o r i a l . h"23 i n t f a c t o r i a l ( i n t n )4 {5 i f ( n < 0)6 {7 r e t u r n −1;8 }9

10 i f ( n == 0)11 {12 r e t u r n 1 ;13 }14 r e t u r n n ∗ f a c t o r i a l ( n − 1 ) ;15 }

12

Page 13: Tests unitaires : Utilisation de la librairie CUnit

Lancement du test I

1 i n t main ( )2 {3 CU_pSuite p S u i t e = NULL ;45 // I n i t i a l i s e s the CUnit t e s t r e g i s t r y6 i f ( C U _ i n i t i a l i z e _ r e g i s t r y ( ) != CUE_SUCCESS)7 {8 r e t u r n CU_get_error ( ) ;9 }

1011 // Adds a s u i t e to the r e g i s t r y12 p S u i t e = CU_add_suite ( " S u i t e " , NULL , NULL ) ;13 i f ( p S u i t e == NULL)14 {15 CU_c leanup_reg i s t r y ( ) ;16 r e t u r n CU_get_error ( ) ;17 }

13

Page 14: Tests unitaires : Utilisation de la librairie CUnit

Lancement du test II

1 // Adds a t e s t to the s u i t e2 i f ( CU_add_test ( pSu i te , " t e s t o f f a c t o r i a l ( ) " ,3 t e s t _ f a c t o r i a l ) == NULL)4 {5 CU_c leanup_reg i s t r y ( ) ;6 r e t u r n CU_get_error ( ) ;7 }89 // Runs a l l the t e s t s u s i n g the CUnit Bas i c i n t e r f a c e

10 CU_basic_set_mode (CU_BRM_VERBOSE) ;11 CU_bas ic_run_tests ( ) ;12 CU_c leanup_reg i s t r y ( ) ;1314 r e t u r n CU_get_error ( ) ;15 }

14

Page 15: Tests unitaires : Utilisation de la librairie CUnit

Exécution de CUnit

15

Page 16: Tests unitaires : Utilisation de la librairie CUnit

Structure des tests I

Pour les suite de testssetup appelé avant chaque test

tearDown appelé après chaque test

Test Registry

Test Suite 1 ... Test Suite n

Test 11 ... Test 1m Test n1 ... Test nm

16

Page 17: Tests unitaires : Utilisation de la librairie CUnit

Structure des tests

Fonctions de base pour gérer et exécuter des tests

Fonction Description

CU_initialize_registry initialise le test registryCU_add_suite() ajoute une suite de tests dans un test registryCU_add_test() ajoute un test dans une suite de testsCU_console_run_tests exécute les tests en mode console (interactif)CU_cleanup_registry nettoie le test registry

Différents modes d’exécution des tests

Mode Fonction Exécution

Automatique CU_automated_run_tests automatique vers fichier XMLBasique CU_basic_run_tests automatique vers sortie standardConsole CU_console_run_tests interactive en consoleCurse CU_curses_run_tests interactive en interface graphique console

17

Page 18: Tests unitaires : Utilisation de la librairie CUnit

Assertions

Test d’une condition qui doit valoir TRUE

La fonction de test continue en cas d’échec sauf avec xxx_FATAL

Fonctions CU_PASS et CU_FAIL

Utilisées pour forcer la réussite ou l’échec d’un test

Fonction Test

CU_ASSERT (int expr) ou CU_TEST (int expr) expr 6= 0CU_ASSERT_TRUE (val) ou CU_ASSERT_FALSE (val) val = TRUE ou val = FALSE

* CU_ASSERT_EQUAL (actual, expected) actual = expected* CU_ASSERT_PTR_EQUAL (actual, expected) actual = expected* CU_ASSERT_PTR_NULL (value) value = NULL* CU_ASSERT_STRING_EQUAL (actual, expected) actual = expected* CU_ASSERT_NSTRING_EQUAL (actual, expected) actual [0 :n − 1] = expected [0 :n − 1]* CU_ASSERT_DOUBLE_EQUAL (actual, expected, epsilon) |actual − expected | ≤ |epsilon|

* Existent en version négative : CU_ASSERT_NOT_EQUAL, CU_ASSERT_PTR_NOT_EQUAL...18

Page 19: Tests unitaires : Utilisation de la librairie CUnit

Gestion du test registry

Initialisation CU_ErrorCode CU_initialize_registry (void)

CUE_SUCCESS en cas de succès et CUE_NOMEMORY sinon

Nettoyage void CU_cleanup_registry (void)

À faire pour libérer toute la mémoire allouée pour le test registry

19

Page 20: Tests unitaires : Utilisation de la librairie CUnit

Gestion des suites de test

Ajout d’une suite de test CU_pSuite CU_add_suite (const char*

strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean)

CUE_SUCCESS, en cas de succèsCUE_NOREGISTRY, si le registre de test n’est pas initialitéCUE_NO_SUITENAME, si le nom de la suite est NULLCUE_DUP_SUITE, si une suite avec le même nom existe déjàCUE_NOMEMORY, si pas assez de mémoire

Une suite de tests doit porter un nom unique

On peut spécifier des fonctions d’initialisation et de nettoyage

20

Page 21: Tests unitaires : Utilisation de la librairie CUnit

Gestion des tests

Ajout d’un test CU_pTest CU_add_test (CU_pSuite pSuite, const

char* strName, CU_TestFunc pTestFunc)

CUE_SUCCESS, en cas de succèsCUE_NOSUITE, si la suite de tests est invalide ou NULLCUE_NO_TESTNAME, si le nom du test est NULLCUE_NO_TEST, si la fonction de test est invalide ou NULLCUE_DUP_TEST, si un test avec le même nom existe déjàCUE_NOMEMORY, si pas assez de mémoire

Un test doit porter un nom unique au sein de sa suite

21

Page 22: Tests unitaires : Utilisation de la librairie CUnit

Exemple 2 : Pile I

1 typede f s t r u c t s t a c k {2 i n t s i z e ;3 s t r u c t node ;4 } s t a c k ;5 s t r u c t node {6 i n t v a l u e ;7 s t r u c t node ∗ next ;8 } ;9

10 // C r e a t e s a new s t a c k11 //12 // Retu rns a p o i n t e r to the new s t a c k13 // or NULL i f not enough memory14 s t a c k ∗newStack ( ) ;1516 // Pushes a new v a l u e on the s t a c k17 //18 // Retu rns 1 i f the v a l u e has been pushed on the s t a c k19 // or −1 o t h e r w i s e20 i n t push ( s t a c k ∗ s , i n t v a l u e ) ;

22

Page 23: Tests unitaires : Utilisation de la librairie CUnit

Exemple 2 : Pile II

1 // Pops a v a l u e from the s t a c k2 //3 // Retu rns the popped v a l u e from the s t a c k i f any4 // or NULL o t h e r w i s e5 vo id pop ( s t a c k ∗ s ) ;67 // Gets the top v a l u e from the s t a c k8 //9 // Retu rns the top v a l u e from the s t a c k i f not empty

10 // or NULL o t h e r w i s e11 vo id top ( s t a c k ∗ s ) ;1213 // Gets the s i z e o f the s t a c k14 //15 // Retu rns the s i z e o f the s t a c k16 i n t s i z e ( s t a c k ∗ s ) ;1718 // F r e e s the s t a c k19 //20 // Retu rns 0 i f the s t a c k has been s u c c e s s f u l l y f r e e d21 // or −1 o t h e r w i s e22 i n t f r e e S t a c k ( s t a c k ∗ s ) ;

23

Page 24: Tests unitaires : Utilisation de la librairie CUnit

Initialisation et nettoyage de la suite

1 #i n c l u d e " s t a c k . h"2 #i n c l u d e " CUnit / Bas i c . h"34 s t a t i c s t a c k ∗ s = NULL ;56 i n t i n i t _ s u i t e ( vo id )7 {8 i f ( ( s = newStack ( ) ) != NULL)9 {

10 r e t u r n 0 ;11 }12 r e t u r n −1;13 }1415 i n t c l e a n _ s u i t e ( vo id )16 {17 f r e e S t a c k ( s ) ;18 r e t u r n 0 ;19 }

24

Page 25: Tests unitaires : Utilisation de la librairie CUnit

Procédure de test

1 vo id t e s t _ s i z e ( vo id )2 {3 CU_ASSERT_EQUAL ( s i z e ( s ) , 0 ) ;45 i f ( push ( s , " H e l l o " ) )6 CU_ASSERT_EQUAL ( s i z e ( s ) , 1 ) ;7 i f ( push ( s , " I " ) && push ( s , "am" ) && push ( s , "God" ) )8 CU_ASSERT_EQUAL ( s i z e ( s ) , 4 ) ;9

10 top ( s ) ;11 CU_ASSERT_EQUAL ( s i z e ( s ) , 4 ) ;1213 i f ( pop ( s ) != NULL)14 CU_ASSERT_EQUAL ( s i z e ( s ) , 3 ) ;15 i f ( pop ( s ) != NULL && pop ( s ) != NULL16 && pop ( s ) != NULL)17 CU_ASSERT_EQUAL ( s i z e ( s ) , 0 ) ;18 i f ( pop ( s ) == NULL)19 CU_ASSERT_EQUAL ( s i z e ( s ) , 0 ) ;20 }

25