Tests unitaires : Utilisation de la librairie CUnit

764 vues

Publié le

Cette présentation concerne le développement piloté par les tests (TDD, Test-Driven Development). Cette méthodologie se base sur des tests unitaires qui testent de manière indépendante des unités de code (module, procédure/fonction, classe...). En particulier, cette présentation utilise la librairie CUnit utilisée pour le langage C.

Publié dans : Technologie
0 commentaire
1 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
764
Sur SlideShare
0
Issues des intégrations
0
Intégrations
3
Actions
Partages
0
Téléchargements
9
Commentaires
0
J’aime
1
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Tests unitaires : Utilisation de la librairie CUnit

  1. 1. EX4C Systèmes d’exploitation Tests unitaires Utilisation de la librairie CUnit Sébastien Combéfis mardi 3 mars 2015
  2. 2. Ce(tte) œuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution – Pas d’Utilisation Commerciale – Pas de Modification 4.0 International.
  3. 3. 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 objectifs Trouver rapidement des erreurs Sécuriser la maintenance Documenter le code Utilisés en TDD, et en Extreme Programming (XP) 3
  4. 4. 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
  5. 5. 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
  6. 6. 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
  7. 7. 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
  8. 8. 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
  9. 9. 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 tests Non-interactive (résultat en XML) Interactive en console (ANSI C) ou graphique (curses) http://cunit.sourceforge.net/ 9
  10. 10. 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 of an i n t e g e r 2 // 3 // Returns the f a c t o r i a l of n 4 // or −1 i f n < 0 5 i n t f a c t o r i a l ( i n t n ) ; 10
  11. 11. 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 / Basic . h" 3 4 void t e s t _ f a c t o r i a l ( void ) 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); 8 9 CU_ASSERT ( f a c t o r i a l (0) == 1 ) ; 10 11 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) == 720); 14 } 11
  12. 12. Implémentation de la fonction 1 #i n c l u d e " f a c t o r i a l . h" 2 3 i n t f a c t o r i a l ( i n t n ) 4 { 5 i f ( n < 0) 6 { 7 return −1; 8 } 9 10 i f ( n == 0) 11 { 12 return 1; 13 } 14 return n ∗ f a c t o r i a l ( n − 1 ) ; 15 } 12
  13. 13. Lancement du test I 1 i n t main () 2 { 3 CU_pSuite pSuite = NULL ; 4 5 // I n i t i a l i s e s the CUnit t e s t r e g i s t r y 6 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 return CU_get_error ( ) ; 9 } 10 11 // Adds a s u i t e to the r e g i s t r y 12 pSuite = CU_add_suite ( " S u i t e " , NULL, NULL ) ; 13 i f ( pSuite == NULL) 14 { 15 CU_cleanup_registry ( ) ; 16 return CU_get_error ( ) ; 17 } 13
  14. 14. Lancement du test II 1 // Adds a t e s t to the s u i t e 2 i f ( CU_add_test ( pSuite , " t e s t of 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_cleanup_registry ( ) ; 6 return CU_get_error ( ) ; 7 } 8 9 // Runs a l l the t e s t s using the CUnit Basic i n t e r f a c e 10 CU_basic_set_mode (CU_BRM_VERBOSE) ; 11 CU_basic_run_tests ( ) ; 12 CU_cleanup_registry ( ) ; 13 14 return CU_get_error ( ) ; 15 } 14
  15. 15. Exécution de CUnit 15
  16. 16. Structure des tests I Pour les suite de tests setup 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
  17. 17. Structure des tests Fonctions de base pour gérer et exécuter des tests Fonction Description CU_initialize_registry initialise le test registry CU_add_suite() ajoute une suite de tests dans un test registry CU_add_test() ajoute un test dans une suite de tests CU_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 XML Basique CU_basic_run_tests automatique vers sortie standard Console CU_console_run_tests interactive en console Curse CU_curses_run_tests interactive en interface graphique console 17
  18. 18. 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 = 0 CU_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
  19. 19. 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
  20. 20. 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ès CUE_NOREGISTRY, si le registre de test n’est pas initialité CUE_NO_SUITENAME, si le nom de la suite est NULL CUE_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
  21. 21. 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ès CUE_NOSUITE, si la suite de tests est invalide ou NULL CUE_NO_TESTNAME, si le nom du test est NULL CUE_NO_TEST, si la fonction de test est invalide ou NULL CUE_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
  22. 22. Exemple 2 : Pile I 1 typedef s t r u c t stack { 2 i n t s i z e ; 3 s t r u c t node ; 4 } stack ; 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 // Creates a new stack 11 // 12 // Returns a p o i n t e r to the new stack 13 // or NULL i f not enough memory 14 stack ∗ newStack ( ) ; 15 16 // Pushes a new v a l u e on the stack 17 // 18 // Returns 1 i f the v a l u e has been pushed on the stack 19 // or −1 o t h e r w i s e 20 i n t push ( stack ∗s , i n t v a l u e ) ; 22
  23. 23. Exemple 2 : Pile II 1 // Pops a v a l u e from the stack 2 // 3 // Returns the popped v a l u e from the stack i f any 4 // or NULL o t h e r w i s e 5 void pop ( stack ∗ s ) ; 6 7 // Gets the top v a l u e from the stack 8 // 9 // Returns the top v a l u e from the stack i f not empty 10 // or NULL o t h e r w i s e 11 void top ( stack ∗ s ) ; 12 13 // Gets the s i z e of the stack 14 // 15 // Returns the s i z e of the stack 16 i n t s i z e ( stack ∗ s ) ; 17 18 // Frees the stack 19 // 20 // Returns 0 i f the stack has been s u c c e s s f u l l y f r e e d 21 // or −1 o t h e r w i s e 22 i n t f r e e S t a c k ( stack ∗ s ) ; 23
  24. 24. Initialisation et nettoyage de la suite 1 #i n c l u d e " stack . h" 2 #i n c l u d e " CUnit / Basic . h" 3 4 s t a t i c stack ∗ s = NULL ; 5 6 i n t i n i t _ s u i t e ( void ) 7 { 8 i f (( s = newStack ( ) ) != NULL) 9 { 10 return 0; 11 } 12 return −1; 13 } 14 15 i n t c l e a n _ s u i t e ( void ) 16 { 17 f r e e S t a c k ( s ) ; 18 return 0; 19 } 24
  25. 25. Procédure de test 1 void t e s t _ s i z e ( void ) 2 { 3 CU_ASSERT_EQUAL ( s i z e ( s ) , 0 ) ; 4 5 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 ) ; 12 13 i f ( pop ( s ) != NULL) 14 CU_ASSERT_EQUAL ( s i z e ( s ) , 3 ) ; 15 i f ( pop ( s ) != NULL && pop ( s ) != NULL 16 && 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

×