Tests unitaires : solutions théoriques à un besoin réel Dans un récent projet de développement, nous avons décidé, ou plutôt tenté d’adopter un environnement de tests unitaires pour tester notre logiciel. Celui-ci étant développé sous Microsoft .NET en C#, nous avions à choisir entre les environnements NUnit et MbUnit. Après avoir consulté quelques blogues et groupes de discussions, nous avons opté pour MbUnit puisqu’il était décrit comme étant plus facilement extensible. Ce n’est pas tout d’avoir sous la main un des meilleurs environnements de tests unitaires, encore faut-il savoir s’en servir adéquatement. C’est alors que nous nous sommes posé plusieurs questions, dont certaines demeurent partiellement ou totalement sans réponse : Que devons-nous tester? Devons-nous adopter une approche « boite blanche » dans laquelle nous nous soucions du détail de l’implantation de chaque méthode, au point d’avoir un cas de test pour couvrir chacune des boucles et conditions? Devons-nous plutôt nous concentrer sur le service que rend chaque méthode (celle privée aussi ???) sans s’arrêter au détail de la plomberie? Et si une méthode modifie simplement l’état interne de l’objet, est-ce correct de faire appel à la réflexion pour consulter la valeur des attributs privés? Nous avons consulté plusieurs livres, dont Test-Driven Development in Microsoft .NET et Pragmatic Unit Testing in C# with Nunit. Malheureusement, je trouve que les exemples dans ces livres manquent radicalement de réalisme. Il est plutôt rare dans la pratique professionnelle que nous ayons à monter des cas de test pour une structure de données aussi simple qu’une pile (stack). C’est une toute autre affaire quand on utilise des fonctionnalités avancées comme Windows Communication Foundation, où un client et un serveur sont requis afin de rendre le tout fonctionnel. Comme nous ne voulions pas que nos tests unitaires prennent l’allure de tests d’intégration dans lesquels, pour un seul test, nous devions instancier 4 ou 5 objets de classes différentes, l’utilisation d’environnements comme Rhino Mocks s’avérait nécessaire pour remplacer certains objets en reproduisant leur comportement sans utiliser leur réelle implantation. Encore là, plusieurs contraintes d’utilisation lorsque nous avions besoin de simuler le comportement d’objets que nous n’avions pas développé nous-mêmes. Afin de mettre une limite à ce que nous testions, nous avons fait l’hypothèse que toutes les librairies externes que nous utilisions (Framework .NET, WCF, Log4Net, etc.) sont exemptes de bogue. Ainsi, nous n’avions pas à vérifier que tel élément s’insère correctement dans une collection.Il ne fait aucun doute que l’automatisation des tests unitaires représente un outil indispensable pour la phase de développement, mais surtout pour la phase de maintenance où les tests de régression prennent une place prépondérante. Mais l’application des différents outils disponibles dans la communauté est pour ma part bien moins évidente. Tant que les applications demeurent de niveau académique, tout va bien. Mais, lorsque la complexité de celles-ci augmente, j’ai l’impression qu’une bonne dose d’expérience est nécessaire afin de tirer le meilleur de ces outils de tests.Les clients que nous rencontrons dans notre pratique en RS&DE; nous parlent très rarement de leurs expériences avec les tests unitaires. Seulement quelques-uns semblent les utiliser systématiquement, certains les ayant mêmes adaptés et intégrés parfaitement à leur environnement de développement. Faites-nous part de vos expériences, bonnes ou mauvaises. Crédit photo : Elisedelacruz via Pixabay.