Faire des tests unitaires avec Visual Studio 2010

| Alexandre Meyer (Soat) | Soat |

Vous avez entendu parler des tests unitaires, vous voulez en faire, mais il vous manque le comment ?

D'accord pour faire des tests unitaires, mais sans écrire des milliers de lignes de code, sans réinstaller autre chose ?

Visual Studio, votre IDE favori a déjà la solution.

Tout d'abord, nous allons rappeler des notions de base sur les tests unitaires, puis présenter l'outil, ce qu'il offre. Ensuite, on va le comparer avec la concurrence.

L'article s'ouvrira enfin sur l'opportunité de passer à une licence supérieure avec les coûts associés et enfin les apports du passage à Visual Studio 2012 en ce qui concerne les TU.

Je vous proposerai alors des retours d'expériences sur l'usage que j'ai pu en faire lors de mes missions.

N'hésitez pas à donner vos avis sur cet article sur le forum. Commentez

- Titre : Faire des tests unitaires avec Visual Studio 2010

- Auteurs : Alexandre Meyer (Soat), Soat

- Parution : 21 octobre 2014

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2014 Alexandre Meyer (Soat). Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Pourquoi Tester ?

- I-A. Les raisons liées au projet

- I-A-1. Pour l'équipe

- I-A-2. Pour vous-mêmes

- I-B. Ce qu'est un test unitaire

- I-B-1. Définition

- I-B-2. Ses caractéristiques à la définition

- I-B-3. Ses caractéristiques à l'exécution

- II. Présentation de « MS Test »

- II-A. Historique

- II-B. Fonctionnement de l'outil

- II-B-1. Les vues

- II-B-1-a. Test View

- II-B-1-b. Test List Editor

- II-B-1-c. Tests Results

- II-B-1-d. Test Runs

- II-B-2. Anatomie d'un test unitaire

- II-B-2-a. Les Attributs

- II-B-2-a-i. TestClass

- II-B-2-a-ii. ClassInitialize

- II-B-2-a-iii. ClassCleanup

- II-B-2-a-iv. TestInitialize

- II-B-2-a-v. TestCleanup

- II-B-2-a-vi. TestMethod

- II-B-2-a-vii. ExceptionExpected

- II-B-3. Configuration des tests unitaires

- II-B-3-a. Les différentes manières de créer un test unitaire

- II-B-3-b. Spécificités de l'outil

- II-B-3-b-i. Les tests introspectifs

- II-B-3-b-ii. MultiCœur

- II-B-3-b-iii. Gestion Du MTA

- II-B-3-b-iv. DataDriven Tests : DDT

- II-B-3-b-iv-I. Les tests génériques :

- III. MsTest face à ses concurrents

- III-A. Ses avantages face à NUnit

- III-A-1. Son Intégration

- III-A-2. Complètement multithread et Multicœurs

- III-B. Ses limites

- IV. Mon retour d'expérience

- IV-A. Expérience chez un intégrateur de produits embarqués automobiles

- IV-A-1. Mon retour

- IV-A-2. Le retour de mon Client

- IV-B. Expérience chez un client en e-mailing marketing

- IV-B-1. Problématiques

- IV-B-2. Deux lots à réaliser

- IV-B-3. Les fonctionnalités des tests unitaires ont été

- IV-B-4. Retour client

- IV-B-5. Mon retour

- IV-C. Et les autres versions de Visual Studio ?

- IV-C-1. Les plus de la licence Pro/Ultimate

- V. Visual Studio 2012

- VI. Remerciements

I - Pourquoi Tester ?

I-A - Les raisons liées au projet

- Pour des raisons politiques : l'ordre vient d'en haut (du N+2, par exemple), on n'en connaît pas forcément les raisons.

- Risque de pertes financières : un distributeur de produits financiers qui s'arrête même quelques secondes peut potentiellement entraîner des conséquences pécuniaires.

- Risque létal : un automate embarqué dans un avion.

- Produit grand public : pas d'écran bleu.

- Études : pour valider un POC.

I-A-1 - Pour l'équipe

- Non-régression entre les « commit » grâce à l'intégration continue

En effet, une modification trop vite faite et/ou mal testée pour un besoin spécifique peut répondre au nouveau besoin, mais est-ce que les anciens sont toujours satisfaits ? Et comment le savoir, à moins de replonger dans la documentation ? Ou bien faire Shift+F12 pour savoir que la méthode est appelée par dix autres ?

- Garder la confiance entre les développeurs et la maintenabilité

Lors d'un travail en équipe, les interventions sur un même fichier ou classe sont monnaie courante. Si un « assembly » doit être modifié/remplacé pour une modification ou satisfaction d'un nouveau besoin, il est nécessaire d'être sûr que les fonctionnalités actuelles soient toujours opérationnelles après la modification. Puis vérifier, sur la machine de « Build » grâce à l'intégration continue, que le « merge » éventuel n'entraîne pas de régression.

Les tests unitaires sont un moyen de le garantir.

I-A-2 - Pour vous-mêmes

- Validation couche après couche d'une architecture :

Cette approche est recommandée pour faciliter les tests sur les développements de la couche en cours plutôt que sur les N-1 précédentes couches.

- Faciliter le débogage : tout ce qui est déjà testé par les TU n'est plus à tester lors de la recherche d'un bogue, la recherche est ainsi écourtée.

Les blocs softwares suffisamment testés permettent de débusquer plus vite la faille, plutôt que de tout reprendre en pas-à-pas depuis le début (par exemple, le clic utilisateur). Même si vous ne pouvez pas faire de pas-à-pas, des TU d'échecs permettent de valider des hypothèses.

- Connaître les performances

Comment prouver de manière confortable que tel « use case » répond à la disponibilité, à une charge maximale, et/ou à un temps demandé ? Par des tests unitaires ! Pour chaque dimension de performance demandée, un test unitaire vous permettra d'être sûr d'avoir atteint l'objectif, d'avoir une trace du résultat du test et comment vous l'avez fait.

I-B - Ce qu'est un test unitaire

I-B-1 - Définition

« Le test unitaire est un procédé permettant de s'assurer du fonctionnement correct d'une partie déterminée d'un logicielou d'une portion d'un programme (appelée « unité » ou « module »). »

I-B-2 - Ses caractéristiques à la définition

- Son taux de couverture pour un ensemble de tests.

- Sa réutilisabilité : si oui, y a-t-il des difficultés à le réutiliser ?

- Contexte de départ, contexte d'arrivée (par exemple : démarrer un Windows Service, faire le test unitaire puis arrêter le Windows Service).

- Synchronisme : Synchrone/Asynchrone.

I-B-3 - Ses caractéristiques à l'exécution

- Sa réussite.

- Son temps d'exécution moyen.

- Son Environnement d'exécution : DEV, REC, PREX.

- MTA/STA.

- MonoCœur/MultiCœurs.

II - Présentation de « MS Test »

II-A - Historique

L'infrastructure xUnit a été introduite comme concept de base de « l'eXtreme Programming » en 1998. Cette méthode définissait un mécanisme efficace pour aider les développeurs à créer des tests unitaires automatisés, performants et structurés lors de leurs activités courantes de développement. Depuis lors, cette infrastructure a évolué en véritable norme pour les infrastructures de tests unitaires automatisés. Un des problèmes spécifiques de la mise en place de tests unitaires automatisés et structurés vient de la quantité de codes nécessaire pour l'accomplissement de ces tâches. (Il faut beaucoup de codes pour tester votre code !) Le concept de générateur de code, simplement défini comme « logiciel qui crée du logiciel », s'impose de plus en plus au sein des bureaux de développement informatique des entreprises.

Concept de l'infrastructure xUnit

Équivalent VS 2005 (voir les attributs ci-dessous)

Description

Test

TestMethod

Ce sont vos tests. Fournit la logique pour vérifier que le résultat est bien celui prévu et vous informe si le résultat n'est pas atteint. Imaginez qu'il s'agit de votre « méthode ».

Contexte du test (Fixture)

TestClass

Regroupement logique d'un à plusieurs tests. Imaginez qu'il s'agit de votre « classe ».

Suite de tests

Test List **

Regroupement logique d'un à plusieurs contextes de test. Imaginez qu'il s'agit de votre « bibliothèque de classes ». Remarque : cette liste n'a pas besoin d'attribut.

Testeur

Infrastructure de tests unitaires VS 2005 VSTS

GUI/Application de console chargée de découvrir, d'exécuter et de présenter les résultats des tests. Dans cet article, Visual Studio 2005 Team System servira de testeur.

II-B - Fonctionnement de l'outil

II-B-1 - Les vues

Elles sont au nombre de quatre, mais les deux premières ont en commun un même ensemble de fonctionnalités :

- afficher un ensemble de tests ;

- les trier ;

- modifier les colonnes ;

- aider à la recherche d'un test.

II-B-1-a - Test View

Pour trouver, fabriquez une sélection de test.

II-B-1-b - Test List Editor

Qui sert principalement à afficher des ensembles de tests, à en créer, à préparer une sélection et à lancer une session sur cette sélection.

II-B-1-c - Tests Results

Pour afficher, lancer/relancer en « Release/Debug » les tests unitaires et connaître leurs états.

x

À noter : vous pouvez même relancer la session de test sans la recompilation. Le gain de temps et la liberté de le faire sont appréciables milkoseck 2014-10-30T09:18:34Deux sujets >> sont appréciables.:

- si un test avait échoué là où une ressource indépendante/extérieure était indisponible ;

- si vous étiez en train de retoucher du code pendant une longue session de test, que vous ne pouvez déployer maintenant sans une recompilation.

II-B-1-d - Test Runs

Vous servira surtout si vous pouvez lancer plusieurs sessions de tests. Vous pourrez alors vous y connecter pour suivre le déroulement et annuler une session de tests.

II-B-2 - Anatomie d'un test unitaire

Voici un aperçu d'une classe de test dans Visual Studio :

Une classe de test unitaire se reconnaît grâce à ses attributs. Un attribut est une classe qui fournit des informations au compilateur et est notée entre crochets : [Attribut()]. Le nom de la méthode ou de la classe sous un attribut importe peu, seul l'attribut permet de faire fonctionner les tests. Le fait de mettre un nom de fonction compréhensible est un plus pour la lecture de la classe.

II-B-2-a - Les Attributs

II-B-2-a-i - TestClass

Cet attribut indique que la classe est une classe contenant des tests. Elle sera donc prise en compte lors de l'exploration, lors de la recherche des TU dans la solution et lors de l'exécution des tests.

II-B-2-a-ii - ClassInitialize

La méthode taguée avec cet attribut sera appelée avant le premier test de la classe. Cela permet de créer des informations qui peuvent être reprises dans les tests. Par exemple : on peut créer des fichiers nécessaires aux tests sur le disque.

II-B-2-a-iii - ClassCleanup

Cet attribut indique que la méthode sera appelée après l'exécution du dernier test de la classe. Par exemple : on peut supprimer les fichiers créés sur le disque.

II-B-2-a-iv - TestInitialize

Méthode qui sera exécutée avant chaque test présent dans la même classe. Différent de « ClassInitialize », il est exécuté avant chacun des tests lancés, seul ou en groupe. Donc si par exemple, on doit initialiser des listes, instances et champs de base de données, on pourrait le faire dans cette méthode.

II-B-2-a-v - TestCleanup

Méthode qui sera exécutée après la fin de chacun des tests exécutés appartenant à la même classe. Si on roule plusieurs tests en groupe, cette méthode sera exécutée à la fin de chaque test. Donc par exemple, si on veut remettre un champ de base de données à sa valeur initiale, car on l'a modifié durant le test, on pourrait le faire dans cette méthode.

Comme vous pouvez le constater, il est possible de gérer finement vos tests en leur créant un environnement, que ce soit pour la classe complète (ClassInitialize et ClassCleanup) ou au niveau des tests eux-mêmes (TestInitialize et TestCleanup).

II-B-2-a-vi - TestMethod

Voici l'attribut qui sera le plus utilisé. Il définit un test. Une bonne pratique de test est la méthode des trois A (Arrange/Act/Assert) : chaque méthode de la classe Assert permet de tester un aspect du test unitaire. Si une vérification échoue, une exception spécifique est levée. Cela signifie que le test a échoué. Chaque test unitaire est traité séparément, les autres tests vont donc continuer. Chaque méthode a une version prenant en paramètre une chaîne de caractères. Cette dernière sera incluse en cas d'erreur de vérification.

II-B-2-a-vii - ExceptionExpected

Cet attribut est utilisé sur une méthode de test (attribut TestMethod) afin de s'assurer que l'appel de la méthode à tester génère bien la bonne exception. Cela évite de créer un test unitaire contenant un bloc try…catch.

Exemple :

1. [TestMethod()]

2. [ExpectedException(typeof(Exception))]

3. public void Test()

4. {

5. }

Pour résumer les principaux attributs, voici dans quel ordre les différents attributs seront appelés si je lance les Tests 1 et 2 en une session :

- [ClassInitialize()] ;

- [TestInitialize()] ;

- [TestMethod()] ;

- Test numéro 1… ;

- [TestCleanup()] ;

- [TestInitialize()] ;

- [TestMethod()] ;

- Test numéro 2…. ;

- [TestCleanup()] ;

- [ClassCleanup()] .

Vous n'avez normalement pas à gérer vous-mêmes l'ajout des attributs, Visual Studio les ajoutera lui-même lorsqu'il les crée lors d'une génération.

II-B-3 - Configuration des tests unitaires

Les tests unitaires ont leur propre fichier de configuration, indépendant des célèbres WebConfig et App.Config. Le réglage par défaut suffit à la plupart des tests unitaires, mais si vous voulez, vous pourrez y configurer :

- le déploiement de fichiers ou répertoires spécifique aux tests, car il faut savoir que pour chaque session de tests, « MSTest » va générer un répertoire d'exécution indépendant du répertoire « Debug » ou « Release ». Ce qui de fait rend un peu plus chaque session de test unique si vous avez par exemple manipulé des fichiers.

- le type d'host : Default ou Asp.net ? 32 ou 64 bits ?

- le « Timeout » au niveau solution : vous pouvez y configurer la possibilité d'annuler toute une session de tests si la session dépasse un temps demandé. Et marquer comme échoué un test qui a duré trop longtemps.

- le lancement de scripts : au début et à la fin de la session de tests.

II-B-3-a - Les différentes manières de créer un test unitaire

- Créer des tests à partir de rien (classe de test).

- Créer des tests à partir d'une méthode. La méthode la plus couramment utilisée : un clic droit sur la méthode, « créer un projet de test » ou « sélectionner un projet de test existant ». Et le « skeleton » de la méthode de test sera écrit à l'endroit voulu avec tous les attributs nécessaires.

- Créer des listes de tests : permet de regrouper vos tests par secteurs fonctionnels, classes ou assembly… En effet, quand vous regardez la liste des tests d'une solution, c'est bien tous les tests de chacun des projets que vous verrez, vous aurez ainsi vite besoin de les classer, de les regrouper selon des critères à définir.

- Séquences de tests ordonnées :

- permet de mémoriser, d'exécuter une suite de tests dont l'enchaînement a un intérêt ;

- faire des scénarios de tests : par exemple j'ai pu simuler le comportement d'un utilisateur dans une méthode, puis je l'ai réutilisé pour simuler 50 utilisateurs accédant à ma DAO en cours de développement.

II-B-3-b - Spécificités de l'outil

II-B-3-b-i - Les tests introspectifs

Avez-vous un besoin de tester des méthodes privées ? MsTest vous génère de toute façon le squelette de test sans configuration ou paramétrage supplémentaire. Comment fait-il ? MsTest fait de la réflexion pour « décapsuler » temporairement l'encapsulation de la classe. Vous n'avez donc rien à changer sur votre code métier, et ce « décapsuleur » aussi appelé “accessor” fonctionne sur toute la classe.

II-B-3-b-ii - MultiCœur

Le fonctionnement en Monocœur est le réglage par défaut de MsTest. Chaque test est exécuté par un cœur. Cela va donc à une certaine vitesse… Quand on modifie le réglage en Multicœur, on peut dérouler au maximum autant de tests en parallèle que la machine a de cœur de processeur, comme quatre sur un Core-i7.

Comparaison du temps total de test : oui, cela va bien quatre fois plus vite, j'ai hâte de lancer mes tests sur notre machine de « Build » qui a 12 cœurs… Toutefois, si vous utilisez un worker de test par cœur, attention à l'utilisation des ressources en simultanée par vos tests.

Voici l'astuce, il faut ouvrir  le fichier *.TestSettings avec un éditeur XML et changer l'attribut « parallelTestCount » au nombre de cœurs que vous voulez utiliser.

II-B-3-b-iii - Gestion Du MTA

Définition du MTA : Multi-Threaded Appartment.

C'est l'utilisation de plusieurs threads d'égal à égal à l'intérieur d'un test, et non un « MainThread », plus des « foreground Thread » et « BackGround Thread ».

Voir la figure ci-dessous :

Pour utiliser WaitHandle.WaitAll(WaitHandle[]), le MTA doit être configuré. Cette méthode vous permettra de lancer plusieurs threads d'un coup au travail dans votre test et les attendre en fin de méthode en une seule ligne. Cette dimension est d'autant plus importante si vous voulez faire des tests impliquant des objets COM. Le MTA vous servira pour faire des tests de « Thread-Safe ».

Par exemple :

- tester l'utilisation concurrentielle d'une méthode accédant à une ressource critique ;

- une « webmethod » en WCF, par exemple ;

- voir l'évolution des performances de chaque accès par thread en fonction du nombre d'accès concurrentiels.

À savoir : les performances des tests baissent quand le MTA est activé, donc à n'activer qu'en cas de besoin.

Voici le secret : vous ouvrez le fichier *.TestSettings avec un éditeur XML et ajoutez la balise « Execution Thread » comme indiqué ci-dessous :

<TestSettings>
<Execution>
<!-- ... -->
<ExecutionThread apartmentState="MTA" />
</Execution>
</TestSettings>

II-B-3-b-iv - DataDriven Tests : DDT

Littéralement en Français : tests pilotés par les données.

Le principe consiste à industrialiser les paramètres possibles d'un même test unitaire. Une fois le TU écris, on attache une data source XML, CSV, Database. Lors de l'exécution du TU, la méthode de test sera appelée avec en paramètre, l'une des lignes de la data source. Un exemple pour illustrer ce genre de test : la multiplication.

J'ai trouvé un intérêt pratique à utiliser le DDT en mission.

Une fois que mon serveur de calcul WCF était prêt, je voulais voir s'il acceptait toujours des calculs demandés dans le passé.

Aussi ai-je demandé un dump de la base de production sur la base de recette pour lancer un test massif utilisant des paramètres de calcul passés.

J'ai pu me rendre compte à la fois des performances de calculs sur chaque calcul, faire une moyenne du temps des calculs, et … me poser la question pourquoi certains calculs plantaient… mais voir aussi que mon serveur survivait au plantage des calculs quelle qu'en soit la raison.

II-B-3-b-iv-I - Les tests génériques :

Comment ça les tests génériques ? Vous voulez dire tester les méthodes avec des <T>?

Oui, ces méthodes peuvent être testées aussi.

Prenons un exemple :

Imaginez que vous réimplémentez la liste List<T>, vous la nommez GenericList<T>.

Et elle implémente l'interface suivante :

Pour une première approche, on ne pose pas de contraintes sur le <T>.

Quand on utilise la génération automatique de tests sur la méthode AddHead(), voici ce que nous sort Visual Studio :

Encore une fois, il nous mâche plutôt bien le travail, il génère ainsi la testMethod(), mais aussi une méthode générique intrigante avec Helper à la fin, qui utilise default et est appelée avec GenericParameterHelper.

Bon d'abord, permettez-moi de présenter GenericParameterHelper, car ce type n'existe pas dans les librairies classiques.

Il appartient à l'« Assembly » : Microsoft.VisualStudio.TestTools.UnitTesting.

C'est une classe qui nous aide à tester des types génériques en nous permettant de transmettre des arguments de types non spécifiques. Ainsi, si vous hésitez encore sur les contraintes de type à appliquer sur vos méthodes génériques, vos tests eux, seront déjà prêts.

Mais voici l'explication du pourquoi cette méthode additionnelle :

Puisque les méthodes génériques fonctionnent avec plusieurs types différents, pourquoi réécrire le même test pour la même méthode, même si seuls les types diffèrent ?

Illustration par l'exemple :

J'ai enrichi un petit peu la méthode d'aide en appelant plusieurs fois le « AddHead » et surtout en vérifiant que les éléments insérés étaient présents avec l'Enumerator.

Mais vous aurez surtout remarqué que j'appelle la même méthode plusieurs fois avec des types différents : du temps a encore été gagné.

III - MsTest face à ses concurrents

III-A - Ses avantages face à NUnit

Le TestContext sert à porter des informations d'un test à l'autre, et écrire dans le log du résultat de test.

AreEqual<T> pour faire des tests d'égalité entre objets, utile notamment si vous utilisez Entity Framework.

Assert.Inconclusive est automatiquement ajouté, lors d'une session de tests massifs, ceux marqués comme inconclusives sont considérés aussi comme échoués. Vous savez donc quels tests restent à implémenter.

Pouvoir renseigner les bons contextes de départ et d'arrivée pour les sessions de tests. L'aspect réutilisable d'un test (utilisé seul, ou dans une batterie de tests).

III-A-1 - Son Intégration

Tout d'abord son Intégration à Visual Studio, le temps de mise en place est donc réduit, et le temps de passage entre un test et un codage classique réduit. Pour une intégration similaire avec « NUnit », il faut sortir 160 $ au moins.

III-A-2 - Complètement multithread et Multicœurs

Pour l'exécution de chaque méthode de test, un thread est créé, un répertoire d'exécution est créé ; ce qui garantit une bonne isolation entre chaque session de test et permet d'utiliser intelligemment tous les cœurs des processeurs.

- Génération automatique des Skeletons : il génère automatiquement un Skeleton compilable et prêt à l'emploi directement à partir d'un « assembly » ou d'une méthode, moins de code à écrire donc.

- Maîtrise sur trois niveaux du contexte(Vs Xunit) : en effet, vous pouvez paramétrer les contextes de fin et d'arrivée au niveau tests, chaque classe, et même « Assembly ».

- Les listes ordonnées de tests.

- Les tests introspectifs.

- Supporte le MTA.

- « Timeout » au niveau solution : le TimeOut peut être appliqué à un « Assembly » ou à une méthode.

- Méthodes génériques : c'est seul outil de test que je connais qui peut faire ce genre de test, et ce, alors que le framework 4.0 est sorti depuis 2 ans.

L'exploitation des résultats (le fichier de résultat est un XML) (-Test Unitaires application MVC : http://msdn.microsoft.com/fr-fr/library/ff936235.aspx).

III-B - Ses limites

Un léger coût de démarrage de session de tests au lancement.

Pas d'assertion sur la présence des fichiers et répertoires.

L'intégration continue est moins facile en dehors des outils Microsoft.

DataDriven Test : il faut au moins écrire un CSV pour les tests alors que « NUnit » supporte l'écriture paramétrique des méthodes de test avec les différentes combinatoires en attributs.

Sur les tests Web : les tests unitaires vous permettront de valider les couches moyennes et basses, mais pas celles de l'UI, d'autres outils de TU seront plus adaptés comme WatiN. MSTest ne fournit pas de Mocks, mais l'on pourra cependant compter sur NMock3 (Net 3.5, Net 4.0) et Moq (.Net 4.0). Attention à RhinoMocks (.Net 3.5), plusieurs remontées de bogues incompréhensibles sur stackOverflow ou SocialMsdn ont été signalées.

Pour faire une synthèse :

IV - Mon retour d'expérience

IV-A - Expérience chez un intégrateur de produits embarqués automobiles

Je faisais partie d'une équipe développant un SDK visant un déploiement public pour des applications embarquées sur des voitures. Il présentait de nombreuses fonctionnalités asynchrones, utilisait plusieurs threads, offrait l'accès à des ressources critiques.

IV-A-1 - Mon retour

-Le séquençage de tests : pour simuler un comportement utilisateur sur l'interface bluetooth de la librairie que je codais, j'ai pu énumérer facilement plusieurs cas métiers et prouver à mon chef l'exhaustivité de ceux-ci, puisqu'il y avait accès aussi.

-La possibilité d'écrire les tests juste avec la nouvelle interface du service à implémenter pour les tierces parties. J'avais donc mes tests prêts avant le codage lui-même.

-Le temps limite d'exécution : en effet, les tests duraient souvent plusieurs minutes, et il était nécessaire de préférer faire échouer toute la session de tests si une ressource venait à manquer, plutôt que d'attendre inutilement.

-Automatisation de procédure de test Longue.

Jugez plutôt : allumer l'interface bluetooth, lister les téléphones disponibles, se connecter à un téléphone, télécharger tout le contactbook, déconnecter, recommencer avec l'autre… et éteindre l'interface. Et le temps pour chaque téléphone s'il vous plaît.

-Le chronométrage était essentiel pour certains « uses cases », mon client avait un engagement contractuel sur le temps mis pour récupérer des données dans le contactBook. Je pouvais ainsi me rendre compte plus facilement du gain de temps en modifiant un seul des blocs de code nécessaire à cette demande et en relançant les tests.

-Le séquençage de tests m'a permis de simuler un utilisateur qui connecte son téléphone en bluetooth, passe un appel, raccroche.

Tout cela juste en réutilisant des tests unitaires existants. L'historique des tests me permettait de me rendre compte de l'évolution des performances. Les séances de tests peuvent coûter du temps en exécution, sauf que je faisais autre chose entre temps et réagissait plus vite en cas d'erreur => car un clic sur l'échec du test mène droit à la méthode de test.

IV-A-2 - Le retour de mon Client

« L'écriture des tests a eu un coût certain, mais cela a permis de se poser les bonnes questions à propos de la compréhension du fonctionnel et de vérifier si les cas métiers ont bien été tous prévus.

La génération de code a eu un gain de temps de développement non négligeable sur l'écriture des tests comparé à ce qui avait été tenté avec NUnit. La méthode des tests unitaires par MsTest a eu un succès suffisamment grand dans l'équipe d'Alexandre pour que les autres équipes s'y intéressent et accélèrent leur passage à Visual Studio 2008 pour en bénéficier. »

IV-B - Expérience chez un client en e-mailing marketing

Objectif de la mission : construction d'un serveur WCF de calcul de cible marketing.

IV-B-1 - Problématiques

Recherche de la performance, souci récurrent d'accès concurrentiels, mise en cache de données grande en taille (en cumulé >8 Go, ~5 Mo en moyenne par unité de cache). Pérennité paramétrable de la validité des calculs. Mise en file du calcul (un calcul dure 15 minutes en moyenne), engagement chiffré sur la disponibilité du service.

IV-B-2 - Deux lots à réaliser

- Système de mise en cache de données volumineuses avec accès concurrentiels, réglage du délai de validité du cache.

- Système de priorisation d'accès aux caches en lecture ou écriture selon les droits configurés des clients accédants.

IV-B-3 - Les fonctionnalités des tests unitaires ont été

- L'utilisation du MTA

- Le Chronométrage

- Les Stress Tests

Pour vérifier l'aspect « thread-safe » d'accès au cache.

-Recherche des limites du service par des tests unitaires appelant d'autres tests unitaires en boucle, et multithread pour simuler une demande massive de calcul.

IV-B-4 - Retour client

« Les découvertes de bogues ont été bien plus précoces, donc plus faciles à corriger, car les tests ont été faits en parallèle du développement de la couche testée. »

« La recherche du même bogue en production aurait été quasi impossible, car le nombre de couches logicielles à tester aurait été beaucoup plus élevé qu'en période de tests unitaires ».

IV-B-5 - Mon retour

Au moment de bâtir une architecture d'accès « thread-safe » niveau après niveau, j'ai choisi de valider soigneusement, à l'aide des tests unitaires, la couche en cours, avant d'attaquer la suivante. Ainsi, en cas de bogue, je cherchais d'abord à remettre en cause le niveau en cours de développement. La connaissance des performances a été essentielle dans cette mission, car le développement s'est fait en deux lots : tout d'abord une mise en cache sur disque dur, puis une priorisation des flux de demande de calcul en fonction de la charge logicielle et des règles métier. Il était donc essentiel de bien connaître toutes les caractéristiques du premier lot fini avant d'attaquer le deuxième.

IV-C - Et les autres versions de Visual Studio ?

IV-C-1 - Les plus de la licence Pro/Ultimate

- Combien ça coûte ?

- Et si le chef peut sortir le chéquier…

- Code metrics : dans notre cas, permet de cerner rapidement les codes les plus complexes et les plus critiques à tester.

- Code Coverage : donne une idée de la couverture de vos tests sur votre code.

- Database Unit Test : vérifie le comportement d'objets en base comme les procédures stockées.

- Test Impact Analysis : savoir que la modification d'un code métier aura un impact sur vos tests.

- Test Data Generation : générateur personnalisé pour remplir vos tables afin de mener vos tests.

- Web Testing : le must du must, vous manipulez votre site Web comme un utilisateur et celui-ci enregistre et rejoue à volonté votre scénario qui est modifiable et extensible. Attention toutefois de ne pas chercher à manipuler des types trop complexes sur la page Web, des retours d'expérience ont montré que cela ne fonctionnait plus au-delà d'une certaine complexité.

V - Visual Studio 2012

Visual Studio 2012 reprend beaucoup de fonctionnalités de VS2010. On en voit quelques nouvelles, comme explicité sur la copie d'écran ci-dessous, on peut désormais relancer un sous-ensemble de tests en fonction de leurs statuts (échoués, réussis, non exécutés…).

- Code Clone Detection : si vous avez l'impression de revoir souvent les mêmes blocs de code, cette fonctionnalité vous ravira !

- Analyseur de code : sert à analyser la qualité du code d'une application sans l'exécuter. L'analyseur examine votre code à la recherche d'un ensemble d'erreurs courantes et du non-respect d'une bonne approche en matière de programmation.

- Microsoft Fakes isolation framework : enfin du Mocking ! MSTest ne fournissait pas de base dans VS2010, voilà un manque comblé.

- Extend the unit test type : comme son nom l'indique, permet de faire des extensions du Framework de MSTest, ce que « NUnit » proposait déjà.

- MSTest & NUnit utilisables tous les deux en totale transparence : Visual Studio 2012 permet d'utiliser paraît-il, les deux aussi facilement, et en toute transparence.

VI - Remerciements

L'équipe de la rédaction .NET remercie sincèrement Soat de nous avoir autorisés à publier cet article sur Developpez.com. Soat est une société de conseil spécialisée dans l'accompagnement de ses clients, tout au long du cycle de vie de leurs projets et le développement de technologies Java et Web.

Nous remercions également Vincent VIALE pour la mise au gabarit et Malick SECK pour sa relecture orthographique.

N'hésitez pas à donner vos avis sur ce tutoriel sur le forum. Commentez