Test unitaire
Impossible d'accéder à la ressource audio ou vidéo à l'adresse :
La ressource n'est plus disponible ou vous n'êtes pas autorisé à y accéder. Veuillez vérifier votre accès puis recharger la vidéo.
Objectif.
Savoir écrire un test unitaire simple.
Mise en situation
Une première approche des tests est celle du test unitaire. Il s'agit de tester chaque composant, chaque fonction de notre programme de manière isolée.
Imaginez un programme de gestion d'une association, et qui est donc en charge de plusieurs fonctionnalités : gérer les cotisations, la comptabilité, les dons effectués, etc. Le programme est composé de très nombreuses fonctions, comme par exemple une fonction qui calcule un abattement fiscal sur un don. L'idée du test unitaire sera d'écrire un test qui va se charger de lancer cette fonction plusieurs paramètres différents, et de s'assurer que le résultat est toujours celui que l'on attend.
Rappel : Test unitaire
Le but d'un test unitaire est de vérifier le bon fonctionnement d'une composante d'un programme, le plus souvent une fonction. Le test unitaire essaiera d'être exhaustif en vérifiant que chaque ligne de code est viable et ne provoque pas d'erreur. Par exemple, si une fonction contient une condition, il faudra au moins deux tests : un dans lequel la condition est vraie et l'autre dans lequel la condition est fausse.
Fondamental :
On appellera test unitaire une fonction qui appelle de multiples fois une autre fonction afin de tester sa validité selon différents paramètres.
Méthode : Couverture de code
Une ligne de code est considérée comme couverte par un test si elle est exécutée durant le test.
Pour couvrir complètement le code, il faut tester la fonction avec différentes valeurs permettant de vérifier toutes les conditions.
Les conditions doivent être couvertes car elles sont souvent à l'origine de bugs.
Les frameworks de test permettent de calculer facilement la couverture de son code.
Exemple : Tester les valeurs retournées
Voici un exemple de test sur une fonction simple. Si le résultat attendu n'est pas identique à celui retourné par la fonction, le test échoue et affiche un message d'erreur.
/** JavaScript : teste unitairement la fonction backetPrice. */
function basketPrice (listItemPrices) {
let res = 0
for (let i = 0; i < listItemPrices.length; i++) {
res = res + listItemPrices[i]
}
return res
}
function testBasketPrice () {
if (basketPrice([2, 5, 29]) !== 36) {
console.log('Test échoué totalPanier pour [2, 5, 29]')
return false
}
if (basketPrice([]) !== 0) {
console.log('Test échoué totalPanier pour []')
return false
}
console.log('Test totalPanier réussi')
return true
}
testBasketPrice()
"""Python : teste unitairement la fonction backet_price. """
def basket_price(list_item_prices):
res = 0
for i in range(len(list_item_prices)):
res = res + list_item_prices[i]
return res
def test_basket_price():
if basket_price([2, 5, 29]) != 36:
print("Test échoué basket_price pour [2, 5, 29]")
return False
if basket_price([]) != 0:
print("Test échoué basket_price pour []")
return False
print("Test basket_price réussi")
return True
test_basket_price()
Si lors d'une modification du code, une erreur est introduite, par exemple :
for (let i = 0; i < listItemPrices.length - 1; i++)
Le test échouera et affichera :
Test échoué totalPanier pour [2, 5, 29]
Ainsi, l'erreur est détectée et corrigeable avant que les utilisateurs n'expérimentent le bug directement.
Complément : Utiliser la syntaxe assert
Pour simplifier les tests, il est possible d'utiliser un nouvel élément de syntaxe : l'assertion. Une assertion ne fera rien de particulier si l'expression qui la suit est vraie mais une erreur sera émise si l'expression est fausse (AssertionError
pour être précis).
/** JavaScript : teste unitairement la fonction backetPrice en utilisant des assert. */
function basketPrice (listItemPrices) {
let res = 0
for (let i = 0; i < listItemPrices.length; i++) {
res = res + listItemPrices[i]
}
return res
}
function testBasketPrice () {
const assert = require('assert')
assert(basketPrice([2, 5, 29]) === 36)
assert(basketPrice([]) === 0)
console.log('Test totalPanier réussi')
return true
}
testBasketPrice()
"""Python : teste unitairement la fonction total_panier en utilisant des assert. """
def basket_price(list_item_prices):
res = 0
for i in range(len(list_item_prices)):
res = res + list_item_prices[i]
return res
def test_basket_price():
assert basket_price([2, 5, 29]) == 36
assert basket_price([]) == 0
print("Test basket_price réussi")
return True
test_basket_price()
Exemple :
Voici un programme qui teste une fonction renvoyant la liste des prix TTC à partir des prix HT :
/** JavaScript : teste unitairement la fonction htToTtc. */
function htToTtc (htPriceList) {
const ttcPriceList = []
for (let i = 0; i < htPriceList.length; i++) {
const ttcPrice = htPriceList[i] * 1.2
ttcPriceList.push(ttcPrice)
}
return ttcPriceList
}
function testHtToTtc () {
if (htToTtc([2, 5, 10]).toString() !== [2.4, 6, 12].toString()) {
console.log('Test htToTtc échoue pour [2, 5, 10]')
return false
}
if (htToTtc([]).toString() !== [].toString()) {
// On teste également les valeurs extrêmes
console.log('Test htToTtc échoue pour [2, 5, 10]')
return false
}
console.log('Test réussi')
return true
}
testHtToTtc()
"""Python : teste unitairement la fonction HT_to_TTC. """
def HT_to_TTC(ht_price_list):
ttc_price_list = []
for i in range(len(ht_price_list)):
ttc_price = ht_price_list[i] * 1.2
ttc_price_list.append(ttc_price)
return ttc_price_list
def test_HT_to_TTC():
if HT_to_TTC([2, 5, 10]) != [2.4, 6, 12]:
print("Test HT_to_TTC échoue pour [2, 5, 10]")
return False
if HT_to_TTC([]) != []: # On teste également les valeurs extrêmes
print("Test HT_to_TTC échoue pour []")
return False
print("Test réussi")
return True
test_HT_to_TTC()
Complément : Mocker des variables
Un développeur Web écrira des fonctions faisant des requêtes web ou vers des bases de données.
Dans le cadre d'un test, ces appels ne seront pas possibles car on ne peut se permettre d'interroger les systèmes en production. Pour pallier ce problème, il est possible d'utiliser des mocks qui remplacent certaines variables par une valeur pré-définie.
À retenir
Un test unitaire vérifie automatiquement le comportement d'une fonction, avec des valeurs simples et des valeurs extrêmes.
Un bon test unitaire doit prévoir tous les cas d'utilisation de la fonction testée.
Impossible d'accéder à la ressource audio ou vidéo à l'adresse :
La ressource n'est plus disponible ou vous n'êtes pas autorisé à y accéder. Veuillez vérifier votre accès puis recharger la vidéo.