This post is only available in French

A qui est destiné ce document

Ce document est à l'attention des développeurs ayant de bonnes connaissances techniques. En revanche il est intéressant pour un chef de projet de connaître les généralités énoncées dans la première partie du document.

Généralité

Qu'est ce qu'un test unitaire

D'après Wikipédia :

En programmation informatique, le test unitaire est un procédé permettant de s'assurer du fonctionnement correct d'une partie déterminée d'un logiciel ou d'une portion d'un programme (appelée « unité » ou « module »). On écrit un test pour confronter une réalisation à sa spécification.
Ils consistent en liste de tests à valider afin d'être conforme à la documentation fonctionnelle. Ces tests doivent être exécutés le plus souvent possible au cours de la réalisation, en effet ils permettent en autre de mettre en évidence toutes régression dans le processus de développement.

Pré-requis à l'écriture des tests

Pour écrire les tests unitaires, nous avons besoin dans un premier temps de lister les fonctionnalités : chaque tests doit refléter une fonctionnalité (la plus précise possible). Si les fonctionnalités évolue dans le temps, les tests doivent refléter ces changements.
Dans le monde idéal du TDD, chaque test doit être écrit avant le code permettant de répondre à sa fonctionnalité : de cette manière on peux vérifier que le test failli bien si la fonctionnalité n'existe pas.

Mise en œuvre

Quoi tester ?

Il y a certains éléments qui peuvent difficilement (mais pas impossible !) être testé : envoie d'email, interfaces graphiques, l'interfaçage avec des outils externes, etc... C'est pour cela qu'il est important d'écrire des méthodes répondant à une fonction précise du cahier des charges, mais il sera impossible de tout tester.

L'assertion

L'assertion est la plus petite unité de test, elle doit-être le plus simple possible. Toutes complexités doivent-être prohibé dans les tests et doivent chacun mettre en avant qu'une fonction précise du cahier des charges.

Cas pratique

Voici un cas de mise en oeuvre avec JUnit :

import org.junit.*;
import static org.junit.Assert.*;

public class SampleTest {

    @Before
    public void setUp() {
        // exécuté avant chaque test
    }

    @After
    public void tearDown() {
        // exécuté après chaque test
    }

    @Test
    public void testCondition1() {
        assertIsTrue(condition1);
    }

    @Test
    public void testCondition2() {
        assertIsFalse(condition2);
    }

}

Dans l'ordre seront exécutés :

SampleTest::setUp();
SampleTest::testCondition1();
SampleTest::tearDown();
SampleTest::setUp();
SampleTest::testCondition2();
SampleTest::tearDown();

Vous remarquerez que dans cet exemple tous les tests sont exécutés les uns après les autres. Si un test échoue les autres sont tout de même exécuté. Dans d'autres environnement ils pourraient être tous exécuté en parallèle. Voici un exemple en Javascript en utilisant expresso pour tester une application web (complexe) :

var assert = require('assert');
 , server = require('express').createServer();

assert.response(server, {
    url: '/', timeout: 500
}, {
    body: 'foobar' // vérifie que le corps de la requête HTTP contient 'foobar'
});

assert.response(server, {
    url: '/',
    method: 'GET'
}, {body: '{"name":"tj"}', // vérifie le contenu du corps de la requête HTTP, son statusCode et ses headers
    status: 200,
    headers: {
        'Content-Type': 'application/json; charset=utf-8',
        'X-Foo': 'bar'
    }
});

assert.response(server, {
    url: '/foo',
    method: 'POST',
    data: 'bar baz'
}, {
    body: '/foo bar baz', // vérifie les données renvoyées par le serveur quand on poste un formulaire
    status: 200
}, 'Test POST');

Bonnes pratiques

Des tests simples

Plus les tests sont simples et leur description explicite, plus ils sont efficaces car ils mettent facilement en évidence les problèmes de réalisation face aux spécifications.

Un test == une fonctionnalité

Il ne faut surtout oublier aucune fonctionnalité dans les tests mis en œuvre : il est en effet très dangereux de penser être en sécurité si ils manquent des tests.

Ne pas mettre en doute l'interpréteur

Il existe des tests inutiles, par exemple le test ci-dessous : Assert::areEquals(1 + 2, 3);
Dans le cas présent il est inutile de tester cette assertion. Il s'agit d'un test qui pourrait faire partie des tests unitaires de l'interpréteur (compilateur, VM, etc...), mais pas de votre projet.

Pas de (bon) tests inutiles

Mieux vaut écrire trop de (bon) test que pas assez. En effet, même si chaque tests doivent refléter la fonctionnalité la plus précise il faut écrire un maximum de test.

Annexes

Junit FAQSimpleTestExpresso

Swift macro : @VisibleForTesting

As an ancient Java developer, I’ve learned to use a set of annotations to bring meta programming in my projects. Meta programming can be ...… Continue reading

Dark Mode iOS Snapshot

Published on January 10, 2021

Git-gone

Published on December 31, 2020