name: inverse layout: true class: center, middle, inverse --- # Inès de Courchelle ## Les tests ## 2023-2024 ![image](../img/CY-tech.png) --- layout: false # TODAY ## Objectifs - Utiliser des directives préprocesseurs - Manipuler des arguments d'entrées - Réaliser des tests unitaires - Anticiper les bugs d'un programme --- # TODAY ## Plan 1. Les directives préprocesseurs 2. Les arguments 3. Les tests unitaires --- # TODAY ## Plan 1. .under[Les directives préprocesseurs] 2. Les arguments 3. Les tests unitaires --- # Les directives préprocesseurs ## Définition Directive exécutée lors de la première phase de la compilation ## Pourquoi ? - l'incorporation de fichiers source (#include), - la définition de constantes symboliques et de macros (#define), - la compilation conditionnelle (#if, #ifdef,...) ## On n'en a déjà fait ! ```c #ifndef __puissance4_H_ #define __puissance4_H_ #define N 7 #endif ``` --- # Les directives préprocesseurs ## Exemple 1
--- # Les directives préprocesseurs ## VAR
--- # Les directives préprocesseurs ## Exemple 2 On rajoute les 2 fichiers suivants :
--- # Les directives préprocesseurs ## Exemple 2
--- # Les directives préprocesseurs ## VAR
--- # Les directives préprocesseurs ## Exemple 2 on rajoute les instructions préprocesseurs et ça marche ! ## VAR
--- # La directive \#define ## Objectifs - Des constantes symboliques, - Des macros avec paramètres. ## Définition de constantes symboliques ```c #define NB_LIGNES 10 #define NB_COLONNES 33 #define TAILLE_MATRICE NB_LIGNES * NB_COLONNES ``` #### On a déjà fait ! --- # La directive \#define ## Des macros Une macro avec paramètres se définit de la manière suivante : ```c #define nom(param1,param2) contenu de la macro ``` ## Exemple ```c #define MAX(a,b) (a > b ? a : b) ``` Le processeur remplacera dans la suite du code toutes les occurences du type ```c MAX(x,y) ```
--- # La directive \#define ## Des macros ```c #define MAX(a,b) (a > b ? a : b) ``` - Elle prend 2 paramètres a et b .arrow[] la signature de la macro : MAX(a,b) - Elle renvoie a ou b .arrow[] le corps de la macro (a > b ? a : b) - si a > b alors je renvoie a - si a < b alors je renvoi b
--- # La directive \#define ## le code ```c #include
#include
#define MAX(a,b) (a > b ? a : b) int main(){ int x,y; printf("veuillez saisir x :\n"); scanf("%d",&x); printf("veuillez saisir y :\n"); scanf("%d",&y); printf("le plus grand entre x= %d et y=%d est %d \n",x,y,MAX(x,y)); return 0; } ``` --- # La directive \#define ## VAR
--- # La compilation conditionnelle ## Objectifs - Incorporer ou d'exclure des parties du code source dans le texte qui sera généré par le préprocesseur - Adapter le programme au matériel ou à l'environnement sur lequel il s'exécute - Introduire dans le programme des instructions de débogage
--- # La compilation conditionnelle ## Objectifs - Incorporer ou d'exclure des parties du code source dans le texte qui sera généré par le préprocesseur - Adapter le programme au matériel ou à l'environnement sur lequel il s'exécute - .under[Introduire dans le programme des instructions de débogage]
--- # La compilation conditionnelle ## Algo Calculer la moyenne à partir de plusieurs notes. ```c PROGRAMME maMoyenne VARIABLES nbNotes : entier tabNotes : pointeur d'entier moyenne : reel DEBUT ECRIRE("Combien de notes voulez-vous saisir ?") LIRE(nbNotes) moyenne <- 0 POUR i allant de 0 à nbNotes FAIRE ECRIRE("La note n°"+i+"est :") LIRE(tabNotes[i]) moyenne <- moyenne+ tabNotes[i] FIN POUR moyenne<-moyenne/nbNotes ECRIRE("La moyenne est : "+moyenne) FIN ``` --- # La compilation conditionnelle ## Mon programme sans DEBUG ```c int nbNotes; int* tabNotes; double moyenne; printf("Combien de notes voulez-vous saisir ? \n"); scanf("%d",&nbNotes); moyenne=0; tabNotes = malloc(sizeof(int)*nbNotes); for (int i=0;i
--- # La compilation conditionnelle ## Mon programme avec DEBUG ```c int nbNotes; int* tabNotes; double moyenne; printf("Combien de notes voulez-vous saisir ? \n"); scanf("%d",&nbNotes); moyenne=0; tabNotes = malloc(sizeof(int)*nbNotes); #ifdef DEBUG printf("nbNotes : %d \n",nbNotes); printf("moyenne : %.2lf \n",moyenne); #endif for (int i=0;i
--- # TODAY ## Plan 1. Les directives prépocesseurs 2. .under[Les arguments] 3. Les tests unitaires --- # Les arguments ## Définition Paramètres/valeurs transmis au programme sous la forme de chaînes caractère. Le séparateur des arguments est l'espace. ## Objectifs - Donner des valeurs à des variables même si le code est compilé - Automatiser des exécutions de code - Réaliser des tests - ... --- # Les arguments ## Représentation schématique
## En ligne de commande ```bash ./exe Mike Wheeler ``` ## Résultat
--- # Les arguments en C ## Le prototype de la fonction main .underR[Attention :] il ne faut pas oublier de bien définir la fonction main ```c int main(int argc, char* argv[]) ``` ## Explication - .under[int argc] est le nombre d'arguments passé au programme. Le nombre est toujours supérieur ou égal à 1 car le premier argument est le nom de l'exécutable - .under[char* argv[]] est le tableau de chaînes contenant les paramètres passés au programme --- # Exemple ## Le code ```c #include
#include
int main(int argc, char* argv[]){ printf("Bonjour, %s %s, Comment vas tu ?\n",argv[1],argv[2]); return 0; } ``` ## Compilation ```bash gcc -Wall bonjour.c -o exe ``` ## Exécution ```bash ./exe Mike Wheeler ``` --- # Exemple ## Le code ```c #include
#include
int main(int argc, char* argv[]){ printf("Bonjour, %s %s, Comment vas tu ?\n",argv[1],argv[2]); return 0; } ``` ## Backstage
--- # Exemple ## VAR
--- # Exemple Générique ## Le code ```c #include
#include
int main(int argc, char* argv[]){ for (int i=0; i
--- # Les arguments ## Attention Un argument est toujours une chaîne de caractères ... même si l'argument est un nombre ## C-a-d ```c #include
#include
int main(int argc, char* argv[]){ int somme; somme=argv[1]+argv[2]; printf("la somme est %d \n",somme); return 0; } ```
.pull-left[ #### Compilation ```bash gcc -Wall arg.c -o exe ``` ] .pull-right[ #### Exécution ```bash ./exe 4 4 ``` ] --- # Les arguments ## Attention ```c #include
#include
int main(int argc, char* argv[]){ int somme; somme=argv[1]+argv[2]; printf("la somme est %d \n",somme); return 0; } ```
--- # Exemple 2 ## VAR
--- # La solution ## atoi Conversion des chaînes de caractères en valeur numérique via la fonction atoi() ## Le code ```c #include
#include
int main(int argc, char* argv[]){ int somme; somme=atoi(argv[1])+atoi(argv[2]); printf("la somme est %d \n",somme); return 0; } ``` --- # Exemple 2 ## VAR
--- # Attention ## Ne pas oublier int main (.underR[int argc, char* argv[]]) #### Sinon ça marche pas ## VAR
--- # TODAY ## Plan 1. Les directives préprocesseurs 2. Les arguments 3. .under[Les tests unitaires] --- # Les Tests ## Différents types - test unitaires : - test d'intégration - test de validation - test de régression ## Déroulement des tests 1. choix d'un cas de test (CT) 2. Création d'une donnée de test (DT) pour CT 3. Prévoir un résultat attendu pour DT (ORACLE) 4. Exécuter le code à tester sur DT 5. Comparer le résultat avec l'Oracle grâce aux assestions --- # Les tests unitaires ## Définition .otro-blockquote[C'est une procédure permettant de vérifier le bon fonctionnement d'une partie précise d'un logiciel ou d'une portion d'un programme (appelée « unité » ou « module »). *source : wikipedia*] ## Que Tester ? - Toutes les conditions d'arrêt des boucles itératives - Toutes les branches d'exécution d'une instruction conditionnelle - Les différentes structures de données locales --- # Exemple 1 ## Palindrome #### ALGO ```c FONCTION estPalindrome(mot : tableau de chaine de caractères): ENTIER VARIABLES : i,res,j : entier DEBUT res<-0 i <- 0 j <- strlen(mot) -1 TANT QUE((i <> j) ET (mot[i]=mot[j])) FAIRE i <- i+1 j <- j-1 FIN TANT QUE res <- (i=j); RETOURNER res; FIN ``` --- # Exemple 1 ## Palindrome #### VAR
--- # Exemple 1 ## Palindrome #### Debuggage
--- # Exemple 1 ## Palindrome #### C'est long de tester
--- # Exemple 1 ## Palindrome #### La solution : les arguments
--- # Les assertions ## Définition .otro-blockquote[Une assertion est une expression qui doit être évaluée comme vraie. Si cette évaluation échoue elle peut mettre fin à l'exécution du programme, ou bien lancer une exception. *(source : wikipedia)*] ## Dans notre cas ```c palindrome('kayak') = 1; palindrome('radar') = 1; palindrome('coucou') = 0; palindrome('n') = 1; palindrome('') = 1; ``` --- # Les procédures de tests ## Objectifs - tester les assertions définies avant - automatiser les tests ## Dans notre cas #### RAPPEL ```c PROCEDURE testPalinKAYAK VARIABLE mot : tableau de chaine de caractères DEBUT mot <- "kayak" SI(estPalindrome(mot) ALORS ECRIRE("palindrome('kayak') SUCCEED !") SINON ECRIRE("palindrome('kayak') FAIL !") FIN SI FIN ``` --- # Les procédures de tests ## COMMENT ? Une procédure par assertions ## EN C ```c void testPalinKAYAK(){ char mot[TAILLE]="kayak"; if (estPalindrome(mot)) printf("palindrome('kayak') SUCCEED ! \n"); else printf("palindrome('kayak') FAIL ! \n"); } ``` --- # Le programme de tests ## COMMENT ? Programme principal qui appel toutes les procédures tests ## LES FICHIERS
--- # Le programme de tests ## VAR
--- # Conclusion ## Outil après compilation Les arguments permettent d'adapter un programme à l'utilisateur. On peut modifier les entrées du programme sans recompiler le code. ## Outil pour le debbugage Les directives préprocesseur permettent : - d'établir la compilation conditionnelle - de réaliser des macros ## Outil pour tester un programme Les tests unitaires, en plusieurs étapes : 1. Les assertions 2. Les procédures 3. Le programme test --- # La doc ## Des liens utiles
practicalprogramming -> test unitaire
openClassroom -> les directives du préprocesseur