Accueil
Accueil Le Club Delphi Kylix C C++ Java J2EE DotNET & C# Visual Basic Access Pascal Dev Web PHP ASP XML UML SQLSGBD Windows Linux Autres

Tests Unitaires sous Visual Studio et TFS 2008

Date de publication : 27/12/2007

Par Ludovic Stumme (despeludo.developpez.com)
 

Utilisation du framework de tests unitaires pour une mise en oeuvre d'une démarche TDD sous Visual Studio et TFS 2008.

I. Introduction
II. Principes fondamentaux de la démarche TDD
III. Sujet d'étude
IV. Création de tests unitaires sous Visual Studio 2008
IV-A. Génération automatique de tests unitaires sous Visual Studio
IV-B. Création manuelle de tests unitaires sous Visual Studio
IV-C. Tests unitaires de la classe d'étude
V. Le Framework de tests unitaires de Visual Studio
V-A. Projets et classes de test
V-B. Assertions
V-C. Gestion des exceptions
V-D. Exécution des tests unitaires
V-E. Gestion des listes de tests unitaires
V-F. Couverture de code par les tests unitaires
VI. Les tests unitaires avec Team Foundation Server 2008
VI-A. Référencement du fichier vsmdi
VI-B. Référencement des projets de tests
VI. Conclusion


I. Introduction

A la fin des années 90, Kent Beck et Ward Cunningham élaborèrent une nouvelle approche du développement logiciel appelée Développements Pilotés par les Tests (TDD, Tests Driven Developments). Cette méthode est fondée sur un cycle de développement permettant de paralléliser l'écriture de tests unitaires et du code.

Initialement éprouvée sur de gros projets en SmallTalk, elle fut rapidement portée à l'ensemble des langages modernes dont C#, pour lequel deux principaux framework existent :

    • NUnit, initié par la communauté Open Sources
    • Le framework de test de Microsoft, directement intégré à l'environnement Visual Studio ainsi qu'à l'usine de développement Team Foundation Server.

Le présent article tente de montrer un panel des possibilités du framework de tests de Microsoft.


II. Principes fondamentaux de la démarche TDD

TDD représente une nouvelle manière d'envisager le développement logiciel qui préconise d'écrire des jeux de tests unitaires pouvant être rejoués rapidement, automatiquement et à tout moment.
Un test unitaire est un procédé qui permet de s'assurer du fonctionnement correct d'une portion d'un programme. Il s'agit, pour le programmeur, de tester un module indépendamment du reste du reste du programme, afin de s'assurer qu'il répond à ses intentions.
Dans un contexte de développement objet, on parle souvent de tests sur le contrat : quels services doivent être rendus par une classe ? De ce fait, on ne cherchera à tester de manière unitaire que la partie publique d'une classe : les méthodes, les constructeurs et les propriétés.

La mise en pratique de cette technique de développement permet de répondre facilement aux questions suivantes :

    • Que fait le code ? Les tests unitaires permettent de donner le mode d'emploi du code.
    • Le code est-il facilement modifiable ? Le simple fait de rendre son code testable conduit nécessairement à un design plus modulaire.
    • Peut-on modifier le code sans risque ? La couverture de l'ensemble du code par les tests unitaires permet de se prémunir de tout phénomène de régression.
Les modalités pour mettre en œuvre la démarche sont particulièrement simples et reposent sur le cycle de développement suivant :

    1. Ajouter rapidement un nouveau test
    2. Exécuter tous les tests et constater l'échec du nouveau test : Zone rouge
    3. Ecrire le code minimal permettant de faire passer le test
    4. Exécuter tous les tests et constater qu'ils passent tous : Zone Verte
    5. Remanier le code pour éliminer les duplications : rester en zone verte
S'assurer qu'un test échoue peut paraître curieux mais permet de s'assurer que, d'une part, il est nécessaire d'écrire du code supplémentaire, et d'autre part que le test pourra échouer en cas d'effet de bord conduisant à une régression.


III. Sujet d'étude

Afin de présenter concrètement comment mettre en œuvre cette démarche au sein de Visual Studio, nous allons réaliser une classe un peu triviale, certes compte tenue de la richesse du framework, permettant d'indexer des chaînes de caractères dans une liste.
Le contrat de la classe est le suivant :

  • Nom : IndexList
  • Propriétés :
    • Count : Permet de connaître le nombre d'éléments dans la liste
  • Méthodes publiques :
    • void Add(int index, string chaine) : Ajoute une nouvelle entrée dans la liste
    • string GetValue(int index) : récupère la chaîne associée à l'index
Dans Visual Studio, créez une solution contenant une bibliothèque de classes et créez le squelette de la classe cible. Le résultat devrait ressembler à celui-ci :
C#


    public class IndexList
    {
        public void Add(int index, string chaine)
        {
        }

        public string GetValue(int index)
        {
            return "";
        }

        public int Count{get; private set;}
    }

				
Remarque:
Les valeurs retournées par défaut ne sont présentes que pour faire compiler le code.


IV. Création de tests unitaires sous Visual Studio 2008


IV-A. Génération automatique de tests unitaires sous Visual Studio

Visual Studio intègre un module permettant de générer des tests unitaires à partir d'un code existant. Pour l'activer, placez vous dans votre classe cible et sélectionnez " Create Unit Test …" dans le menu contextuel.
La fenêtre suivante s'ouvre alors :

Génération automatique de tests unitaires

Il vous est alors possible de sélectionner les méthodes que vous souhaitez tester. Dans notre exemple, le code généré est alors le suivant :
C#


    [TestMethod()]
    public void CountTest()
    {
        IndexList target = new IndexList(); // TODO: Initialize 
        int actual;
        actual = target.Count;
        Assert.Inconclusive("Verify the correctness of this test method.");
    }

    [TestMethod()]
    public void GetValueTest()
    {
        IndexList target = new IndexList(); // TODO: Initialize            
        int index = 0; // TODO: Initialize to an appropriate value
        string expected = string.Empty; // TODO: Initialize            
        string actual;
        actual = target.GetValue(index);
        Assert.AreEqual(expected, actual);
        Assert.Inconclusive("Verify the correctness of this test method.");
    }

    [TestMethod()]
    public void AddTest()
    {
        IndexList target = new IndexList(); // TODO: Initialize            
        int index = 0; // TODO: Initialize to an appropriate value
        string chaine = string.Empty; // TODO: Initialize            
        target.Add(index, chaine);
        Assert.Inconclusive("A method that does not return a value cannot be verified.");
    }

    [TestMethod()]
    public void IndexListConstructorTest()
    {
        IndexList target = new IndexList();
        Assert.Inconclusive("TODO: Implement code to verify target");
    }
			
				
Visual Studio génère ainsi des squelettes de tests unitaires à raison d'un test par méthode et par propriété. Avec l'expérience, vous vous rendrez vite compte que cela n'est généralement pas suffisant, mais cela représente une bonne base de travail.
Pour le moment, commentez l'ensemble des méthodes sauf le test de la méthode Add par lequel nous allons commencer.
De la même manière que générer le projet de tests, vous pouvez ajouter automatiquement des tests unitaires, au fur et à mesure que vous ajoutez des méthodes à la définition de vos classes.
Dans notre solution ont également été créés :

  • Le nouveau projet de tests
  • Un répertoire SolutionItems contenant deux fichiers
    • un fichier testRunConfig
    • un fichier vsmdi
Nous reviendrons un peu plus tard sur l'utilité de ces fichiers.


IV-B. Création manuelle de tests unitaires sous Visual Studio

La création de tests unitaires peut également se faire manuellement.
Ajoutez un projet de tests à votre solution :

Création d'un nouveau projet de tests

Dans le nouveau projet de test ainsi créé, je vous conseille de supprimer les fichiers générés par Visual Studio.
Ajoutez à présent un nouveau test de type Test Unitaire, au projet de test, un fichier nommé ici IndexListTest.cs :

Création d'un fichier de tests unitaires

IV-C. Tests unitaires de la classe d'étude

Nous allons pouvoir créer notre premier test unitaire, sur la méthode Add.
Qu'attend-on de cette méthode ?
Suite à son appel, la valeur de Count doit correspondre au nombre d'éléments ajouté.
Dans la classe IndexListTest ajouter une nouvelle méthode permettant de faire ce test. Pour être compatible avec le framework de test, la méthode doit être public, ne rien retourner et ne nécessiter aucun argument. En revanche, elle doit nécessairement être qualifiée avec l'attribut TestMethod, la classe de tests étant elle-même qualifiée avec l'attribut TestClass.

La question se pose maintenant de savoir comment écrire un test unitaire, étant donné que le code exercé par ce test n'existe pas encore.
La " règle des trois A " permet de guider le développeur :

    • Acteurs : mise en place de l'ensemble des objets concernés ou utiles au test
    • Actions : effectuer une action mettant en œuvre l'objet concerné par le test
    • Assertions : cette partie vérifie un état de l'objet concerné par le test
Dans notre cas nous avons :

    • Acteurs :
      • une instance de la liste
      • une valeur attendue : suite à l'ajout dans la liste, la valeur de Count doit être incrémentée
    • Actions :
      • Ajouter un élément dans la liste
    • Assertions :
      • La valeur de la propriété Count doit être celle attendue.
La mise en œuvre de cette règle se traduit par le code de test suivant :
C#


    [TestMethod]
    public void TestAddIncreaseCount()
    {
        // Acteurs
        IndexList list = new IndexList();
        int expected = list.Count + 1;
            
        // Action
        list.Add(12, "chaine");

        // Assertion
        Assert.AreEqual(expected, list.Count);
    }
			

				
Vous remarquerez dans ce code l'utilisation d'une méthode de la classe Assert : AreEqual qui permet de tester l'égalité de deux valeurs. Nous reviendrons plus loin sur l'ensemble de ces méthodes mais retenez que ce sont ces méthodes qui permettent d'informer le framework du succès ou de l'échec d'un test.
Il ne nous reste plus qu'à lancer le test :

    • Soit en sélectionnant Run Test dans le menu contextuel associé à la méthode
    • Soit en utilisant le raccourci clavier Ctrl+R,Ctrl+T (Run Test)
Nous pouvons constater l'échec du test unitaire :


La question qui se pose alors est : quel code minimal dois-je écrire pour que le test passe ?
Pour le moment, rien de plus que le code suivant :
C#


    public void Add(int index, string chaine)
    {
        ++Count;
    }
			
				
Un peu faible comme implémentation ? Certes mais cela suffit amplement à faire passer ce premier test qui, je le rappelle, ne devra plus jamais repasser au rouge.
De plus, pour le moment, aucun test ne nous contraint à en écrire plus. Rejouons le test :

Et voilà, mission accomplie.
Comment justifier à présent la nécessité d'écrire plus de code dans cette méthode ? Tout simplement en en codant une autre, la méthode GetValue ; le scénario est le suivant : suite à l'ajout d'une valeur indexée dans la liste on doit pouvoir la retrouver (logique non ?) par le biais de cette méthode.
Ecrivons le test unitaire associé en appliquant la méthode des trois A :
C#


    [TestMethod]
    public void TestGetValueRetreivesIndexedValue()
    {
        // Acteurs
        IndexList list = new IndexList();
        string expected = "chaine";
        list.Add(12, expected);

       // Action
       string actual = list.GetValue(12);

       // Assertion
       Assert.AreEqual(expected, actual);
    }
			
				
Nous allons faire une première implémentation n'exploitant volontairement pas les possibilités du framework, juste pour démontrer la puissance des tests unitaires.
Nous allons donc créer une structure de données pouvant contenir un nombre et une chaîne que nous pourrons stocker dans une liste, ce qui va nous donner le code suivant :
C#


    public struct Indexer
    {
        public int Index;
        public string Value;
    }

    public class IndexList
    {
        List<Indexer> table = new List<Indexer>();
        public void Add(int index, string chaine)
        {
            Indexer indexer = new Indexer() { Index = index, Value = chaine};
            table.Add(indexer);
            ++Count;
        }

        public string GetValue(int index)
        {
            foreach (Indexer indexer in table)
            {
                if (indexer.Index == index)
                {
                    return indexer.Value;
                }
            }
            return "";
        }

        public int Count{get; private set;}
    }
			
				
Exécutons à nouveau notre test unitaire, on constate qu'il passe.


Un dernier test unitaire peut être écrit pour exprimer que la fonction GetValue renvoie une chaîne vide si la chaîne n'est pas trouvée.
C#


    [TestMethod]
    public void TestGetValueReturnsNullValueIfIndexNotFound()
    {
        // Acteurs
        IndexList list = new IndexList();
        string expected = "";

        // Action
        string actual = list.GetValue(12);
           
        // Assertion
        Assert.AreEqual(expected, actual);
    }
			
				
Voilà, notre classe est opérationnelle et répond au contrat qu'il lui avait été fixé. Arrivé à ce point, un développeur n'utilisant pas la méthodologie TDD se dirait : " OK, c'est bon, ça marche, on ne touche plus à rien… ", tout simplement par crainte d'introduire des bugs. A l'inverse, pour le développeur travaillant en TDD, le vrai travail commence. Maintenant que notre code est couvert de tests unitaires, on peut tout à fait le retoucher autant qu'on le souhaite. Par exemple, une nouvelle implémentation de la classe IndexList pourrait être la suivante :
C#


    public class IndexList
    {
        Dictionary<int, string> table = new Dictionary<int,string>();

        public void Add(int index, string chaine)
        {
            table.Add(index, chaine);
        }

        public string GetValue(int index)
        {
            string value;
            if (table.TryGetValue(index, out value))
                return value;
            else
                return "";
        }

        public int Count { get { return table.Count; } }
    }
			
				
Refaisons passer l'ensemble des tests unitaires. Nous constatons qu'ils continuent à passer. A partir de là vous devez commencer à sentir le véritable intérêt de travailler avec des tests unitaires. Cette méthode, pour être réellement efficace doit être pratiquée de manière systématique et ce quelles que soient les problématiques de délais de livraison qui vous incombe. Avec la pratique, vous vous rendrez compte que le temps que vous consacrez à écrire des tests unitaires sera largement compensé par le temps que vous ne passerez pas à effectuer de la recherche de bug.


V. Le Framework de tests unitaires de Visual Studio

Les tests unitaires occupent une grande place au sein de Visual Studio. Nous allons à présent essayer de parcourir les plus courantes.


V-A. Projets et classes de test

Un projet de test n'est rien de plus qu'un simple projet de bibliothèque de classes dans lequel a été référencé l'assembly Microsoft.VisualStudio.QualityTools.UnitTestFramework. Une classe contenant des méthodes de test est identifiée comme classe de test par l'attribut TestClass. Une méthode de test est qualifiée par un attribut TestMethod. Cela signifie que techniquement, vous pouvez inclure une classe de test dans n'importe quel type d'assembly, bien que cela ne soit pas vraiment recommandé ; il est souhaitable de séparer le code de production du code de test.
En parcourant la classe de test générée par Visual Studio, on trouve une région " Additional test attributes " permettant de définir un ensemble de méthodes particulières, qualifiées par des attributs distincts. Par défaut, toutes ces méthodes sont commentées. Analysons leur utilité au sein d'un projet de test.
C#


    [ClassInitialize()]
    public static void MyClassInitialize(TestContext testContext) { }
			
				
Une telle méthode, qualifiée de l'attribut ClassInitialize, permet de définir des actions à effectuer lors de la création de la classe de test. Ceci peu être utile dans le cas par exemple où vos tests portent sur l'analyse d'un fichier que vous pouvez créer à la volée dans cette méthode avant d'effectuer vos tests unitaires.
C#


    [ClassCleanup()]
    public static void MyClassCleanup() { }
			
				
Une telle méthode, qualifiée de l'attribut ClassCleanup, permet de définir des actions à réaliser après l'exécution de l'ensemble des tests unitaires de la classe, par exemple, la suppression du fichier créé lors de l'initialisation de la classe.

Vous remarquerez que ces deux méthodes sont statiques et ne peuvent donc affecter des propriétés de la classe. Ces deux méthodes sont généralement peu utilisées dans un contexte de tests unitaires. En revanche, elles peuvent avoir un certain sens dans le cas de tests fonctionnels.
C#


    [TestInitialize()]
    public void MyTestInitialize() { }
			
				
Cette méthode permet d'exécuter du code avant l'exécution de chacun des tests de la classe. Dans notre exemple, en regardant nos tests unitaires, on constate que l'on crée un objet IndexList au début de chaque test. En vue de factoriser notre code il serait possible de mettre cette initialisation dans le code de cette méthode, ce qui nous donnerais :
C#


    [TestClass]
    public class IndexListTest
    {
        IndexList list;
 
        #region Additional test attributes
        [TestInitialize()]
        public void MyTestInitialize() 
        {
            list = new IndexList();
        }

        [TestMethod]
        public void TestAddIncreaseCount()
        {
            // Acteurs
            int expected = list.Count + 1;
            
            // Action
            list.Add(12, "chaine");

            // Assertion
            Assert.AreEqual(expected, list.Count);
        }
        …
        …
    }
			
				
On gagne ainsi en taille de code mais on peut potentiellement perdre en lisibilité ; l'utilisation de cette méthode relève d'avantage d'une affaire de goûts personnels.
C#


    [TestCleanup()]
    public void MyTestCleanup() { }
			
				
Cette méthode permet d'exécuter du code après l'exécution de chacun des tests unitaires. Une méthode analogue est principalement utilisée dans les langages non managés pour appeler les destructeurs des objets initialisés dans la méthode précédente.


V-B. Assertions

Au cours du développement de notre sujet d'étude, nous avons utilisé l'une des méthodes de la classe Assert, la méthode AreEqual. Rappelons que cette classe Assert est propre au framework de tests unitaires et n'a rien a voir avec l'assertion de la classe Debug : Debug.Assert.
Le tableau suivant présente les différentes méthodes de la classe Assert.

Méthode Description
AreEqual Teste l'égalité de deux objets.
AreNotEqual Teste l'inégalité de deux objets
AreSame Teste l'égalité de deux références d'objets
AreNotSame Teste l'inégalité de deux références d'objets
Inconclusive Indique que le test n'est évalué ni à vrai ni à faux
IsFalse Teste qu'une condition est fausse.
IsTrue Teste qu'une condition est vraie.
IsNull Teste qu'une référence d'objet est nulle.
IsNotNull Teste qu'une référence d'objet est non nulle

V-C. Gestion des exceptions

Pour bien comprendre la problématique liée aux exceptions dans le framework de tests unitaires de Visual Studio, le code suivant présente la manière dont est sans doute écrite la méthode IsTrue de la classe Debug :
C#


    public class Assert
    {
        public void IsTrue(boolean b)
        {
        	if(!b)
        	    raise new AssertFailedException();
        }}
			
				
C'est aussi simple que cela. Vous noterez juste, dans ce code le déclenchement systématique d'une exception en cas d'échec du test. Cette manière de procéder est valable pour tout framework de tests unitaires.
Reprenons notre exemple d'étude et supposons que pour empêcher l'ajout de doublons dans notre liste, on déclenche une exception de type DuplicateException en cas de tentative d'ajout d'une clé déjà existante. Dans la plupart des framework de tests unitaires on écrirait ceci :
C#


    [TestMethod]
    public void TestAddRaiseExceptionIfAlreadyInList()
    {
        // Acteurs
        IndexList list = new IndexList();
        string chaine1 = "chaine1";
        string chaine2 = "chaine2";
        list.Add(12, chaine1);
        boolean b = false;
        try
        {
        	list.Add(12, chaine2);
        	b = false;
        }
        catch(DuplicateException e)
        {
			b = true;				        	
        }
        Assert.IsTrue(b);
    }
			
				
Dans ce code, que fait-on ? On cherche à savoir si l'exception a bel et bien été déclenchée lorsque l'on a tenté d'ajouter un deuxième élément avec la clé 12. Mais au final on se retrouve à tester une valeur booléenne. De plus, nous avons dû impliquer un boucle try catch ce qui a une certaine tendance à alourdir le code et à rendre le test moins compréhensible.
Le framework de test de Visual Studio propose une solution plus élégante pour résoudre la problématique des exceptions : l'utilisation de l'attribut ExpectedException. Ce dernier nous permet de spécifier l'exception attendue. Le test unitaire précédent s'écrit alors de la manière suivante :
C#


    [TestMethod]
    [ExpectedException(DuplicateException)]
    public void TestAddRaiseExceptionIfAlreadyInList()
    {
        // Acteurs
        IndexList list = new IndexList();
        string chaine1 = "chaine1";
        string chaine2 = "chaine2";
        list.Add(12, chaine1);
        list.Add(12, chaine2);
    }
			
				
Le code est tout de suite plus lisible non ?


V-D. Exécution des tests unitaires

Visual Studio intègre un ensemble de raccourcis clavier, permettant d'exécuter sélectivement les tests unitaires, qu'il peut être utiles de connaître :

Raccourci Description
Ctrl+R, Ctrl+T Exécute le test courant (celui sous lequel se trouve le curseur)
Ctrl+R, Ctrl+A Exécute l'ensemble des tests unitaires de la solution
Ctrl+R, Ctrl+F Exécute uniquement les tests unitaires qui ont échoués lors de la dernière exécution.
Ctrl+R, Ctrl+C Exécute l'ensemble des tests unitaires contenus dans la classe courante
Ctrl+R, Ctrl+N Exécute l'ensemble des tests unitaires contenus dans le namespace courant

V-E. Gestion des listes de tests unitaires

Souvenez-vous, lorsque nous avons créé notre premier projet de tests unitaires, Visual Studio avait ajouté à notre solution un fichier vsmdi. Ce dernier permet de créer des listes de tests unitaires. En ouvrant ce fichier, sous Visual Studio, vous obtenez la fenêtre suivante :

Pour créer une nouvelle liste de tests, sélectionnez " New Test List… " dans le menu contextuel de " Lists of Tests ". Pour assigner un test à une liste de tests, il vous suffit de faire glisser celui-ci dans la liste de tests cible.
Dans une première approche, les listes de tests peuvent être utilisées pour obtenir une granularité d'exécution de séries de tests plus fine que celles proposées par défaut par les raccourcis clavier.
Pour lancer l'exécution des tests contenus dans la liste, cochez la liste et cliquez sur l'icône .


V-F. Couverture de code par les tests unitaires

Nous entrons à présent dans ce qui représente, a mon avis, la réelle valeur ajoutée de l'intégration d'un framework de test dans l'environnement Visual Studio. Ce dernier nous permet d'identifier rapidement les parties de notre code couvertes ou non par les tests. Lors de la création du projet de test, Visual Studio nous avait créé un second fichier : LocalTestRun.testrunconfig. Ce fichier est notamment utilisé pour définir les projets qui doivent faire l'objet d'une couverture de code.
En ouvrant ce fichier, la fenêtre suivante s'affiche :

L'onglet " Code Coverage " permet de sélectionner les projets qui doivent faire l'objet d'une couverture de code. Nous ne sélectionnerons ici que le projet contenant le code de notre IndexList. La couverture de code du projet de tests unitaires n'a pas réellement d'utilité.
Pour obtenir cette couverture de code, lancez l'exécution de l'ensemble des tests unitaires depuis le fichier vsmdi. (Ctrl+R, Ctrl+A ne permet pas d'obtenir la couverture de code). Suite à cette exécution cliquez sur l'icône pour obtenir la couverture de code.
Dans notre cas simple la couverture de code est de 100%.
En désactivant le test vérifiant que la valeur renvoyée est chaîne vide si l'élément n'est pas dans la liste, nous obtenons l'aperçu de couverture suivant :

Les zones bleues identifient le code couvert par les tests, les zones en rose, le code non couvert. Il vous est ainsi possible de rapidement visualiser les manques potentiels en terme de tests unitaires.


VI. Les tests unitaires avec Team Foundation Server 2008

L'usine de développement Team Foundation Server (TFS), intègre dans son processus de Build, un module d'exécution des tests unitaires. Dans un contexte de travail en équipes, ce dernier permet non seulement de s'assurer que l'ensemble des tests unitaires continuent de passer, mais également de conserver un historique d'exécution des tests unitaires et éventuellement de la couverture de code. Ces données peuvent alors être compilées sous la forme de rapports permettant de suivre au jour le jour te taux de couverture de code par les tests unitaires, comme dans l'exemple suivant :

L'activation de l'exécution des tests unitaires dans un Build TFS s'effectue par modification manuelle du fichier TfsBuild.proj.
On recense principalement deux méthodes :

    • Par référencement du fichier vsmdi
    • Par référencement des projets de tests
Le choix s'effectue selon vos besoins.


VI-A. Référencement du fichier vsmdi

Dans le fichier TfsBuild.proj, une section ItemGroup est particulièrement dédiée aux tests unitaires.
Dans notre exemple, le référencement du fichier vsmdi se ferait ainsi :
MsBuild


    <MetaDataFile Include="$(BuildProjectFolderPath)/TestsUnitaires.vsmdi">
        <TestList>Exemple1;Exemple2</TestList>
    </MetaDataFile>
			
				
Cette définition permet de sélectionner les listes de tests à jouer lors du Build. Le principal avantage de cette méthode est de permettre l'activation automatique de la couverture de code par les tests. Un autre avantage est de sélectionner avec une certaine granularité les tests à effectuer.
En revanche, il peut être nécessaire de devoir entretenir, dans ce fichier de configuration, la liste des listes de tests à exécuter, ce qui peut s'avérer relativement laborieux. De plus dans un contexte de travail collaboratif, l'entretien du fichier vsmdi est d'autant plus difficile que ce fichier, partagé par l'ensemble des développeurs, est souvent à l'origine de nombreux conflits de gestion de configuration.


VI-B. Référencement des projets de tests

Une autre méthode permettant d'exécuter les tests unitaires consiste à référencer directement les projets de test à exécuter. Dans cette même section ItemGroup on écrira alors, dans notre cas :
MsBuild


    <TestContainer Include="$(OutDir)\TestSampleLibrary.dll" />
			
				
Il est tout à fait possible de référencer plusieurs projets de test :
MsBuild


    <TestContainer Include="$(OutDir)\TestProj1.dll;$(OutDir)\TestProj2.dll"/>
			
				
Par ailleurs, en prenant l'habitude de nommer les projets de test suivant un certain pattern il est tout à fait possible d'utiliser ce même pattern pour référencer dynamiquement les projets de test :
MsBuild


    <TestContainer Include="$(OutDir)\Test%2a.dll"/>
			
				
Notez que le %2a est l'équivalent XML de * ; on référence ainsi tout projet obéissant au pattern Test*.dll.

Dans TFS 2005, le gros inconvénient de cette méthode est qu'il n'était initialement pas possible d'activer la couverture de code par les tests. La communauté des développeurs .net a alors vigoureusement réagit et quelques temps plus tard, un PowerTools, maintenant directement inclus dans TFS 2008, permis de résoudre ce problème.
Ainsi, pour activer la couverture de code dans TFS 2008, il suffit de référencer le fichier testrunconfig dans la section PropertyGroup du fichier TfsBuild.proj, de la manière suivante :
MsBuild


    <RunConfigFile>$(SolutionRoot)/ LocalTestRun.testrunconfig</RunConfigFile>
			
				
De cette manière, on profite ainsi non seulement de la souplesse de configuration des séries de tests, ainsi que de la couverture de code et les possibilités d'exploitation des résultats.


VI. Conclusion

Microsoft semble avoir parfaitement intégré la démarche de développement TDD non seulement dans son environnement de développement Visual Studio mais également dans l'usine de développement Team Foundation Server. Les développeurs ont maintenant à leur disposition une solution parfaitement intégrée permettant de répondre aux besoins de cette nouvelle méthodologie de développement.
Charge aux développeurs d'adhérer à cette nouvelle manière de concevoir des applications.



Copyright ©2007  Developpez LLC. Tout droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérets. Cette page est déposée à la SACD.

Vos questions techniques : forum d'entraide Accueil - Publiez vos articles, tutoriels, cours et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones. Nous contacter - Copyright 2000..2005 www.developpez.com