Chapitre 1519 minIntermédiaire
Les tests à l'examen : E7 et E6 SLAM, exercices corrigés
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- lire et expliquer un test JUnit sur papier ;
- écrire les tests d'une règle avec ses valeurs limites ;
- éviter les pièges classiques des questions sur les tests ;
- préparer les tests de ton évolution pour l'E6.
5 exercices corrigés
Au BTS SIO SLAM, les tests tombent à l'écrit E7 « Cybersécurité des services informatiques », où le sujet donne une classe de test à expliquer ou demande d'en écrire une, et à l'E6, où la commission attend des tests qui tournent et un test de non-régression pour l'évolution réalisée. Ce chapitre donne la méthode pour répondre sur papier, la syntaxe JUnit des sujets, les pièges classiques, puis des exercices corrigés au format de l'examen.
Où les tests apparaissent dans les épreuves
| Épreuve | Ce qu'on te demande sur les tests | Où t'entraîner |
|---|---|---|
| E7 SLAM (écrit de 4 h, U7) | Expliquer les cas testés par une classe de test ; écrire un ou plusieurs tests d'une méthode ; trouver le cas manquant ; relier un test à une exigence de sécurité | Ce chapitre, le chapitre Journalisation et tests de sécurité du cours E7 |
| E6 SLAM (pratique et oral) | Des tests automatisés qui tournent dans ton projet ; un test pour l'évolution demandée ; la non-régression ; parfois un rapport de test | Les chapitres 7 et 8 du cours E6 SLAM |
| E5 (oral, bloc 1, les deux options) | Des tests d'intégration et d'acceptation rédigés et effectués, et un rapport de test, pour un service mis à disposition | Le chapitre 14 |
Les sujets d'écrit des sessions 2022 à 2024, quand l'épreuve de cybersécurité s'appelait E6 (U6), restent d'excellents entraînements : les questions de tests y ont la même forme. En 2025, par exemple, le sujet donnait trois tests d'une méthode possedeDroit qui vérifie si un utilisateur a le droit de faire une opération sur une table : il fallait expliquer qu'ils couvraient une table absente des droits (refus), une table et une opération autorisées (accord), et une table connue avec une opération non autorisée (refus).
Lire un test JUnit sur papier
Les sujets d'E7 sont souvent écrits en Java, avec JUnit, parfois en PHP avec PHPUnit ou en C#. Tu n'as pas besoin de connaître Java en détail : les tests se lisent comme ceux de ce cours.
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class CompteUtilisateurTest {
private CompteUtilisateur compte;
@BeforeEach
void setUp() {
compte = new CompteUtilisateur();
}
@Test
void test1() {
for (int i = 0; i < 4; i++) {
compte.enregistrerEchec();
}
assertFalse(compte.estVerrouille());
}
}
| Élément Java (JUnit 5) | Équivalent dans ce cours | Sens |
|---|---|---|
@Test | test(…) en Vitest, [Fact] en xUnit, #[Test] en PHPUnit | Cette méthode est un test |
@BeforeEach (JUnit 4 : @Before) sur setUp() | beforeEach, le constructeur xUnit, setUp() de PHPUnit | Exécutée avant chaque test : chaque test part d'un objet neuf |
assertEquals(attendu, obtenu) | expect(obtenu).toBe(attendu), Assert.Equal(attendu, obtenu) | L'attendu d'abord |
assertTrue(condition), assertFalse(condition) | toBe(true), Assert.True | La condition doit être vraie, ou fausse |
assertNull(x), assertNotNull(x) | toBeNull() | La valeur doit être nulle, ou non |
assertThrows(Exception.class, () -> …) | toThrow, Assert.Throws | L'appel doit lever cette exception |
La méthode pour une question de test
Pour expliquer des tests existants, réponds pour chaque test à trois questions, en une ou deux lignes :
- Quelle situation est préparée ? (dans
setUpet au début du test) - Quelle action est faite ? (l'appel de la méthode testée)
- Quel résultat est attendu, et ce qu'il prouve par rapport à la règle ?
Un tableau rend la réponse claire et rapide à corriger :
| Test | Situation | Action | Attendu | Ce qu'il prouve |
|---|---|---|---|---|
| test1 | Compte neuf | 4 échecs de connexion | Non verrouillé | Le verrouillage n'intervient pas avant le 5e échec |
Pour écrire des tests, procède en quatre temps :
- Lis la règle dans le dossier documentaire et souligne les nombres, les « au plus », les « à partir de », les rôles.
- Liste les cas : le cas nominal, chaque cas refusé, et les valeurs limites de part et d'autre de chaque frontière (chapitre 3).
- Écris les tests dans le langage et le style du sujet : reprends les noms de classes et de méthodes des documents, un comportement par test, l'attendu calculé à la main.
- Justifie en une phrase par test ce qu'il vérifie.
Les pièges classiques à l'écrit
| Piège | Ce qui se passe | La parade |
|---|---|---|
| Ne tester que le cas qui marche | Un contrôle d'accès « testé » sans cas refusé ne prouve rien | Toujours au moins un cas refusé par règle |
| Oublier la valeur limite | « 5 échecs » testé avec 10 échecs : la frontière n'est pas vérifiée | Tester 4 et 5, pas 2 et 10 |
Inverser assertEquals | Le message d'échec annoncerait l'inverse ; le correcteur le remarque | assertEquals(attendu, obtenu) |
| Inventer des méthodes | Le test appelle compte.reinitialiser(), qui n'existe pas dans les documents | Utiliser uniquement les classes et méthodes fournies |
| Plusieurs comportements dans un test | Un seul test pour « verrouille et déverrouille et compte » | Un test par comportement, avec un nom ou un commentaire clair |
| Un attendu recopié du code | Si le code est faux, le test confirme l'erreur | Calculer l'attendu à partir de la règle du sujet |
| Oublier la préparation | Le test utilise compte sans qu'il soit créé | Rappeler ce que fait setUp, ou créer l'objet dans le test |
À l'E6 : ce que la commission regarde
À l'E6, la question n'est pas de réciter, mais de montrer. La commission vérifie :
- que ton projet a des tests automatisés qui tournent, avec la commande dans le README (
npm test,dotnet test,vendor/bin/phpunit) ; - que l'évolution demandée arrive avec ses tests : le cas nominal et au moins deux cas d'erreur (un test pour prouver un calcul et un contrôle d'accès) ;
- qu'une correction arrive avec le test qui reproduit le bug, et que toute la suite reste verte (chapitre 11) ;
- que tu sais expliquer un test, dire ce qu'il prouve et ce qui n'est pas testé ;
- si l'expression des besoins le demande, que tu présentes un rapport de test (chapitre 14).
Exercices type examen
Exercice 1 sur 5 Expliquer les cas testés (type E7) Réussi À revoir
Une application de gestion verrouille un compte après 5 échecs de connexion consécutifs. Une connexion réussie remet le compteur d'échecs à zéro, sauf si le compte est déjà verrouillé : seul un administrateur peut alors le déverrouiller.
public class CompteUtilisateur {
public static final int ECHECS_MAX = 5;
private int nbEchecs = 0;
private boolean verrouille = false;
public void enregistrerEchec() {
nbEchecs++;
if (nbEchecs >= ECHECS_MAX) {
verrouille = true;
}
}
public void enregistrerSucces() {
if (!verrouille) {
nbEchecs = 0;
}
}
public boolean estVerrouille() {
return verrouille;
}
public int getNbEchecs() {
return nbEchecs;
}
}
La classe de test contient setUp et test1 (ci-dessus), et :
@Test
void test2() {
for (int i = 0; i < 5; i++) {
compte.enregistrerEchec();
}
assertTrue(compte.estVerrouille());
}
@Test
void test3() {
compte.enregistrerEchec();
compte.enregistrerEchec();
compte.enregistrerSucces();
assertEquals(0, compte.getNbEchecs());
}
- Explique les cas testés par
test1,test2ettest3. - Quelle règle de la spécification n'est pas testée ? Écris le test manquant en JUnit.
Voir la réponseMasquer la réponse de l'exercice 1
1.
| Test | Situation et action | Attendu | Ce qu'il prouve |
|---|---|---|---|
| test1 | Compte neuf, 4 échecs | Non verrouillé | Le compte n'est pas verrouillé avant le 5e échec (limite inférieure) |
| test2 | Compte neuf, 5 échecs | Verrouillé | Le verrouillage intervient au 5e échec exactement (limite) |
| test3 | Compte neuf, 2 échecs puis un succès | Compteur à 0 | Une connexion réussie remet le compteur à zéro tant que le compte n'est pas verrouillé |
test1 et test2 encadrent la valeur limite : 4 échecs, pas de verrouillage ; 5 échecs, verrouillage.
- La règle « un succès ne déverrouille pas un compte verrouillé » n'est pas testée. C'est pourtant la plus importante pour la sécurité : sans elle, un attaquant qui finirait par trouver le mot de passe débloquerait le compte.
@Test
void test4() {
for (int i = 0; i < 5; i++) {
compte.enregistrerEchec();
}
compte.enregistrerSucces();
assertTrue(compte.estVerrouille());
assertEquals(5, compte.getNbEchecs());
}
Le test vérifie que le compte reste verrouillé et que le compteur n'a pas été remis à zéro. Les boucles for sont courantes dans les sujets pour répéter une action ; dans un projet, on préférerait une petite méthode utilitaire echouer(n) pour garder le test lisible.
Tu avais trouvé ?
Exercice 2 sur 5 Écrire les tests d'une règle (type E7) Réussi À revoir
La politique de mots de passe de l'entreprise impose au moins 12 caractères, dont au moins un chiffre et au moins une lettre majuscule. La méthode statique PolitiqueMotDePasse.estRobuste(String mdp) renvoie true si le mot de passe respecte la politique, false sinon (y compris pour null).
Écris en JUnit une classe de test qui couvre la politique avec le minimum de tests pertinents, et justifie chaque test.
Voir la réponseMasquer la réponse de l'exercice 2
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class PolitiqueMotDePasseTest {
@Test
void accepteDouzeCaracteresAvecChiffreEtMajuscule() {
assertTrue(PolitiqueMotDePasse.estRobuste("Sorbier2027a"));
}
@Test
void refuseOnzeCaracteres() {
assertFalse(PolitiqueMotDePasse.estRobuste("Sorbier2027"));
}
@Test
void refuseSansChiffre() {
assertFalse(PolitiqueMotDePasse.estRobuste("SorbierLogistique"));
}
@Test
void refuseSansMajuscule() {
assertFalse(PolitiqueMotDePasse.estRobuste("sorbier2027abc"));
}
@Test
void refuseNull() {
assertFalse(PolitiqueMotDePasse.estRobuste(null));
}
}
- Le premier test est le cas nominal à la limite : exactement 12 caractères, avec un chiffre et une majuscule. Il prouve que 12 suffit.
- Le deuxième est la limite de l'autre côté : 11 caractères, tout le reste valide. Il prouve que la longueur est vérifiée, et au bon seuil.
- Les troisième et quatrième testent chaque condition seule : chaque mot de passe est assez long et ne manque que d'une chose. Un mot de passe trop court et sans chiffre ne dirait pas laquelle des deux règles a provoqué le refus.
- Le dernier vérifie le cas
null, prévu par la spécification.
Tu avais trouvé ?
Exercice 3 sur 5 Le code ou le test ? (type E6) Réussi À revoir
Pendant l'E6, ton test échoue :
FAIL src/export.test.js > refuse l'export à un salarié
AssertionError: expected 401 to be 403
Le test envoie la requête avec le jeton d'un salarié, et l'API répond 401. La commission te demande si le problème vient du code ou du test. Comment le déterminer, et que réponds-tu dans chacun des deux cas ?
Voir la réponseMasquer la réponse de l'exercice 3
401 signifie « non authentifié » : l'API n'a pas reconnu l'appelant. 403 signifie « authentifié mais pas autorisé ». Le salarié devrait être reconnu, puis refusé : l'attendu 403 est le bon, d'après les conventions HTTP.
Pour trancher, on regarde pourquoi l'authentification échoue :
- si le test fabrique mal le jeton (secret de test absent, en-tête mal écrit comme
Beareroublié), c'est le test qui est faux : « Le jeton de test n'était pas valide ; je le corrige, le test passe à 403, ce qui prouve que la route refuse bien les salariés » ; - si le jeton est valide mais que la route vérifie le rôle avant l'authentification, ou renvoie 401 pour un mauvais rôle, c'est le code : « La route renvoie 401 au lieu de 403 pour un rôle insuffisant ; je corrige le code de statut dans le middleware, et je relance toute la suite pour vérifier la non-régression ».
Dans les deux cas, on ne modifie pas l'attendu pour « faire passer » le test : on cherche qui a raison à partir de la règle (ici, la sémantique des codes HTTP), puis on corrige ce qui est faux.
Tu avais trouvé ?
Exercice 4 sur 5 Vocabulaire (questions de cours) Réussi À revoir
Réponds en une ou deux phrases.
- Quelle est la différence entre un test unitaire et un test d'intégration ?
- Qu'est-ce qu'un test de non-régression ?
- Qu'est-ce qu'un mock ?
- Pourquoi une couverture de code de 100 % ne garantit-elle pas l'absence de bug ?
- À quoi sert un cahier de recette ?
Voir la réponseMasquer la réponse de l'exercice 4
- Un test unitaire vérifie une unité de code (une méthode, une classe) isolée de ses dépendances, en quelques millisecondes ; un test d'intégration vérifie que plusieurs composants fonctionnent ensemble (une route, ses middlewares et la base, par exemple).
- C'est le fait de rejouer, après chaque modification, les tests qui passaient avant, pour vérifier que la modification n'a rien cassé. Après chaque bug corrigé, on ajoute le test qui l'aurait détecté.
- Une doublure de test qui remplace une dépendance et vérifie que le code testé l'appelle comme prévu (par exemple, qu'un courriel est envoyé à la bonne adresse), sans effet réel.
- La couverture mesure les lignes exécutées par les tests, pas les résultats vérifiés : un test sans assertion ou sans valeur limite couvre le code sans détecter ses erreurs, et une règle absente du code n'apparaît dans aucune mesure.
- Il liste les cas de test qui vérifient chaque exigence (préconditions, étapes, résultat attendu) ; la MOA le déroule pendant la recette pour décider si elle accepte la livraison.
Tu avais trouvé ?
Exercice 5 sur 5 Préparer les tests d'une évolution (type E6) Réussi À revoir
Expression des besoins : « Ajoutez à Prêt'Matos la possibilité, pour la logistique, de marquer un matériel "en réparation". Un matériel en réparation ne peut plus être réservé. Les réservations déjà faites sur ce matériel sont conservées, mais la logistique en voit la liste pour prévenir les salariés. »
Pendant la phase de préparation, liste les tests que tu écriras (niveau, situation, résultat attendu), en commençant par les plus importants.
Voir la réponseMasquer la réponse de l'exercice 5
| Ordre | Niveau | Situation | Résultat attendu |
|---|---|---|---|
| 1 | Unitaire | Demande de réservation d'un matériel en réparation | Refusée, motif « matériel en réparation » |
| 2 | Unitaire | Demande sur un autre matériel, disponible | Acceptée (la règle ne touche que le matériel concerné) |
| 3 | Intégration | La logistique marque PC-07 en réparation | 200 ; PC-07 apparaît « en réparation » |
| 4 | Intégration (sécurité) | Un salarié tente de marquer un matériel en réparation | 403 ; état inchangé |
| 5 | Intégration | POST /api/reservations sur un matériel en réparation | Refus (409, conflit avec l'état du matériel) ; aucune réservation ajoutée |
| 6 | Intégration | PC-07 a deux réservations futures, puis passe en réparation | Les deux réservations existent toujours ; la liste des réservations concernées les renvoie à la logistique |
| 7 | Non-régression | Toute la suite existante | Verte |
Les tests 1 et 2 fixent la règle ; 4 est le test de droits, indispensable ; 6 vérifie l'exigence la plus facile à oublier, la conservation des réservations existantes. Si le temps manque, on garde 1, 4, 5 et 7, et on annonce les autres comme « à écrire » dans le rapport.
Tu avais trouvé ?