Numérique et sciences informatiques (spécialité) · Première
Spécification et tests : exercices corrigés de NSI en 1re
Publié le 6 novembre 2026 · Mis à jour le 6 novembre 2026 · Signaler une erreur
L'essentiel
- Une spécification décrit ce qu'une fonction doit faire : les entrées admises et le résultat attendu, sans dire comment le calculer 4.
- Un test confronte le programme à sa spécification : pour une entrée donnée, on compare le résultat obtenu au résultat que la spécification impose 5.
- Un jeu de test réussi ne prouve pas que le programme est juste ; un seul test échoué prouve qu'il est faux.
- Pense toujours aux cas limites : liste à un seul élément, valeur nulle, valeurs égales, bornes d'un intervalle.
- À l'épreuve pratique, la spécification est fournie et un jeu de test avec les réponses attendues peut l'accompagner 2.
Comment utiliser ces exercices
Ces exercices t'entraînent à deux gestes que l'on retrouve partout en programmation : lire une spécification sans la déformer, puis écrire des tests qui la vérifient. Ils sont rangés par difficulté croissante. Prends une feuille ou un éditeur Python, cherche seul, puis ouvre les indices avant la correction.
Les exercices
Exercice 1 Lire une spécification et prévoir le résultat
On donne la spécification suivante.
moyenne(tab)reçoit une liste non vide d'entiers et renvoie leur moyenne arithmétique, sous forme d'un nombre.
- Quelle condition porte sur le paramètre
tab? - On veut tester la fonction avec
tab = [12, 8, 15, 5]. Quel résultat attendu doit-on écrire dans l'assertion ? - Écris l'assertion correspondante.
Donne comme réponse numérique la valeur attendue de la question 2.
Indice 1
Une moyenne arithmétique est la somme des valeurs divisée par leur nombre.
Indice 2
Calcule la somme de 12, 8, 15 et 5, puis divise par 4.
Voir la correction pas à pas
La spécification impose que la liste soit non vide : sinon on diviserait par zéro. C'est une condition sur l'entrée, que doit respecter celui qui appelle la fonction.
On calcule la somme : .
La liste contient 4 valeurs, donc la moyenne vaut .
L'assertion s'écrit
assert moyenne([12, 8, 15, 5]) == 10.
Le résultat attendu vient de la spécification (la définition de la moyenne), pas d'un programme déjà écrit. Remarque que la condition « liste non vide » fait partie de la spécification : on ne teste pas la fonction sur une liste vide, puisque la spécification ne le prévoit pas.
Exercice 2 Écrire un jeu de test pour la parité
Spécification : est_pair(n) reçoit un entier positif ou nul et renvoie True si est pair, False sinon.
- Écris trois assertions : une avec un nombre pair, une avec un nombre impair, une avec la valeur 0.
- On teste la fonction pour tous les entiers de 0 à 9 inclus. Pour combien de ces valeurs le résultat attendu est-il
True?
Indice 1
Zéro est un nombre pair : il est divisible par 2.
Indice 2
Liste les entiers de 0 à 9 et repère ceux dont le reste dans la division par 2 est nul.
Voir la correction pas à pas
Un nombre pair :
assert est_pair(8) == True.Un nombre impair :
assert est_pair(7) == False.Le cas limite 0 :
assert est_pair(0) == True, car 0 est divisible par 2. C'est l'assertion que l'on oublie le plus souvent.Pour la question 2, les entiers pairs entre 0 et 9 sont 0, 2, 4, 6 et 8 : cela fait 5 valeurs pour lesquelles on attend
True.
Un bon jeu de test mélange des cas ordinaires et des cas limites. Ici, 0 est le cas limite : un programme qui teste n % 2 == 0 and n > 0 réussirait les deux premiers tests mais échouerait au troisième.
Exercice 3 Compléter un programme à trous
Spécification : maximum(tab) reçoit une liste non vide d'entiers et renvoie le plus grand élément de la liste, sans modifier la liste.
On te donne le programme à trous suivant.
def maximum(tab):
m = ......
for x in tab:
if ......:
m = x
return m
- Complète les deux trous.
- Explique pourquoi
m = 0serait une mauvaise initialisation. - Écris un jeu de trois tests qui permet de détecter cette mauvaise initialisation.
Indice 1
Il faut initialiser m avec une valeur qui appartient forcément à la liste.
Indice 2
Que renverrait la fonction pour une liste ne contenant que des nombres négatifs si m valait 0 au départ ?
Voir la correction pas à pas
Premier trou :
m = tab[0]. La liste est non vide d'après la spécification, donctab[0]existe, et c'est un candidat valable pour le maximum.Second trou :
x > m. On remplacemdès qu'on rencontre un élément strictement plus grand.Avec
m = 0, une liste de nombres tous négatifs, comme[-4, -2, -9], renverrait 0. Or 0 n'est pas un élément de la liste : la spécification n'est pas respectée.Jeu de test :
assert maximum([3, 9, 5]) == 9(cas ordinaire),assert maximum([-4, -2, -9]) == -2(valeurs négatives, détectem = 0),assert maximum([7]) == 7(liste à un seul élément).
Le deuxième test, avec des valeurs toutes négatives, est celui qui fait échouer la mauvaise version. Choisir des entrées qui visent une erreur plausible est plus efficace qu'accumuler des tests semblables.
Exercice 4 Traquer un bug avec un jeu de test
Spécification : minimum(tab) reçoit une liste non vide d'entiers et renvoie le plus petit élément de la liste.
Un élève propose ce code.
def minimum(tab):
mini = 0
for x in tab:
if x < mini:
mini = x
return mini
On dispose du jeu de test suivant (entrée, résultat attendu) :
| Entrée | Attendu |
|---|---|
[4, 7, 2] |
2 |
[-3, 5] |
-3 |
[10] |
10 |
[0, 1] |
0 |
[-1, -5, -2] |
-5 |
- Pour chaque entrée, détermine le résultat renvoyé par le code de l'élève.
- Combien de tests échouent ?
- Corrige le code.
Indice 1
Au départ, mini vaut 0 : pour qu'il change, il faut rencontrer un élément strictement négatif.
Indice 2
Une liste ne contenant que des valeurs positives renvoie toujours 0 avec ce code.
Voir la correction pas à pas
[4, 7, 2]: aucun élément n'est inférieur à 0, la fonction renvoie 0 au lieu de 2. Échec.[-3, 5]: -3 est inférieur à 0,minidevient -3 ; 5 ne change rien. Renvoie -3 : réussi.[10]: renvoie 0 au lieu de 10. Échec.[0, 1]: aucun élément n'est strictement inférieur à 0, la fonction renvoie 0, ce qui est attendu : réussi (par hasard).[-1, -5, -2]:minipasse à -1, puis -5 ; renvoie -5 : réussi. Au total, 2 tests échouent.Correction : initialiser
mini = tab[0]au lieu demini = 0, exactement comme pour le maximum.
Trois tests sur cinq passent, et pourtant le code est faux : un test réussi ne prouve rien, alors qu'un test échoué prouve qu'il y a une erreur. Le test [0, 1] réussit « par chance » ; c'est pourquoi un jeu de test doit contenir plusieurs entrées qui ciblent la même erreur possible.
Exercice 5 Choisir les valeurs aux bornes
Spécification : mention(note) reçoit une note entière entre 0 et 20 inclus et renvoie une chaîne :
"insuffisant"si la note est strictement inférieure à 10 ;"passable"si la note est au moins 10 et strictement inférieure à 12 ;"assez bien"si la note est au moins 12 et strictement inférieure à 14 ;"bien"si la note est au moins 14 et strictement inférieure à 16 ;"tres bien"si la note est au moins 16.
On adopte la stratégie suivante : pour chacun des quatre seuils (10, 12, 14, 16), on teste la valeur du seuil et la valeur juste en dessous ; on ajoute enfin les deux extrémités 0 et 20 de l'intervalle autorisé.
- Écris les assertions associées aux seuils 10 et 16.
- Combien de tests contient le jeu complet ?
- Pourquoi tester un seuil et la valeur juste en dessous ?
Indice 1
Les erreurs les plus fréquentes sont < à la place de <=, et inversement.
Indice 2
Chaque seuil donne deux tests, auxquels s'ajoutent les deux extrémités.
Voir la correction pas à pas
Seuil 10 :
assert mention(9) == "insuffisant"etassert mention(10) == "passable".Seuil 16 :
assert mention(15) == "bien"etassert mention(16) == "tres bien".Les quatre seuils donnent chacun deux tests, soit tests. On ajoute
mention(0)etmention(20): tests.Si le code contient
note > 10au lieu denote >= 10, seule la valeur 10 le révèle ; et si le code a confondu les branches, la valeur juste en dessous du seuil le montre. Les deux valeurs encadrent la frontière : chacune détecte une erreur que l'autre laisse passer.
Les valeurs aux bornes sont celles où les erreurs de comparaison se produisent. Une valeur au milieu d'un intervalle, comme 13, passerait sans révéler la confusion entre < et <=. Tester les extrémités 0 et 20 vérifie aussi que la fonction accepte tout l'intervalle prévu par la spécification.
Exercice 6 Rédiger la spécification et les tests
On veut écrire une fonction occurrences(tab, v) qui compte combien de fois la valeur v apparaît dans la liste tab.
- Rédige sa spécification : paramètres, conditions éventuelles, résultat.
- Propose quatre tests, dont au moins deux cas limites, et justifie le choix de chacun.
- Quel est le résultat attendu pour
occurrences([2, 5, 2, 2, 7, 5], 2)? - Écris le code de la fonction et vérifie-le avec tes tests.
Donne comme réponse numérique le résultat de la question 3.
Indice 1
Que doit renvoyer la fonction quand la valeur cherchée n'apparaît pas du tout ? Et quand la liste est vide ?
Indice 2
Parcours la liste en incrémentant un compteur à chaque fois que l'élément vaut v.
Voir la correction pas à pas
Spécification :
occurrences(tab, v)reçoit une listetabd'entiers (éventuellement vide) et un entierv; elle renvoie le nombre d'éléments detabégaux àv, sous forme d'un entier supérieur ou égal à 0. La liste n'est pas modifiée.Test ordinaire :
assert occurrences([2, 5, 2, 2, 7, 5], 2) == 3(valeur présente plusieurs fois).Cas limites :
assert occurrences([], 4) == 0(liste vide),assert occurrences([1, 3], 9) == 0(valeur absente),assert occurrences([6, 6, 6], 6) == 3(tous les éléments égaux àv).La valeur 2 apparaît aux positions 0, 2 et 3 : le résultat attendu est 3.
Code :
def occurrences(tab, v):puisn = 0, une bouclefor x in tab:avecif x == v: n = n + 1, etreturn n. Les quatre assertions passent.
Ici, c'est la spécification qui décide : elle autorise la liste vide, donc il faut un test pour ce cas, alors que pour moyenne la liste vide était exclue. Écrire la spécification d'abord, puis les tests, puis le code, est la démarche qui limite le risque de se laisser influencer par le code au moment d'écrire les tests 5.
Les questions qu'on se pose
Si tous mes tests passent, mon programme est-il correct ?
Pas forcément. Un test vérifie le comportement du programme pour une entrée précise ; il ne couvre pas toutes les entrées possibles. Un programme peut réussir tous tes tests et être faux sur une entrée que tu n'as pas essayée, comme dans l'exercice du minimum où trois tests sur cinq passaient. À l'inverse, un seul test échoué suffit à prouver une erreur. On cherche donc des jeux de test variés, avec des cas limites, et on vérifie aussi que les tests font exécuter toutes les instructions du code, ce qu'on appelle la couverture de code 5.
Pourquoi écrire les tests avant le code ?
Un test doit refléter la spécification. Si tu écris le code d'abord, tu risques de te laisser influencer par ce qu'il fait et d'écrire des tests qui valident ses défauts 5. En écrivant d'abord les tests à partir de la spécification, tu fixes ce qui est attendu avant de te demander comment l'obtenir. À l'épreuve pratique, le sujet te fournit d'ailleurs la spécification, parfois avec un jeu de test et les réponses attendues 2 : utilise-les pour contrôler ton programme avant de le rendre.
Sources
- Programmes et ressources en numérique et sciences informatiques — voie générale, Éduscol. Consulté le 6 novembre 2026.
- Ressource officielle Éduscol — Spécification et tests, Éduscol. Consulté le 6 novembre 2026.
- Banque des épreuves pratiques de spécialité NSI, Éduscol. Consulté le 6 novembre 2026.
- Spécification (norme technique), Wikipédia. Consulté le 6 novembre 2026.
- Test unitaire, Wikipédia. Consulté le 6 novembre 2026.
Les numéros dans le texte renvoient à ces sources. Une source qui ne dit pas ce qu'on lui fait dire ? Signale-le.