Dans cet article nous allons découvrir les test unitaires avec .Net Core. Comme vous savez que les tests unitaires font partie du processus de développement, ce qui signifie leurs importances afin de s’assurer la validité des développements réalisés. Dans cet article, nous allons découvrir le framework MSTest de Microsoft. So let’s get started. 

Créer un projet de test sous visual studio

Note

Si vous voulez utiliser la ligne de commande dans .Net Core. Vous pouvez utiliser:

dotnet new mstest

 

Le projet contient trois références importantes dans le répertoire Packages:

  • NET.Test.Sdk
  • TestAdapter
  • TestFramework

 

 

Créer et exécuter un premier test

Pour créer un test unitaire, nous avons besoin de savoir 3 éléments importants:

L’attribut [TestClass] :

Comme son nom l’indique, désigne une classe qui contient les tests unitaires.

L’attribut [TestMethod]

indique une méthode qui est une méthode de test.

 Les trois A (Arrange, Act, Assert)

  • Arrange: A ce niveau, on declare toutes les variables nécessaires y compris les types primitives et complexes.
  • Act: On fait l’appel à la méthode qui sera testée.
  • Assert: On fait la comparaison entre le résultat attendu et le résultat retourné par la méthode. Autremment dit, on valide le comportement de la méthode sous le test.

 

Exemple

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Text;

namespace UnitTestDemo
{
  [TestClass]
  public class MathTests
  {
    [TestMethod]
    public void TestAddOpertion()
    {
      int actuel = MathHelper.Add(1, 1);
      int attendu = 2;
      Assert.AreEqual(attendu, actuel);
    }
  }

  public class MathHelper
  {
    public static int Add(int a, int b) => a + b;
  }
}

 

Dans le code partagé ci-dessus, nous avons crée notre classe de test nommée MathTests, et puis nous l’avons décorée avec l’attribut [TestClass].

L’étape suivante consiste à créer la méthode de test, et dans ce cas nous avons crée la methode TestAddOpertion décorée avec l’attribut [TestMethod] qui est responsable d’assurer la validité du test.

Pour exécuter le test. Dans le menu en haut, cliquez sur Test >> Test Explorer et puis l’icone exécuter le test.

Résultat

 

Explorer les asserts

Précédemment, nous avons crée un test unitaire qui permet de tester l’addition de deux nombres en utilisant la classe Assert.

La classe Assert est très importante puisqu’elle est responsable de tester la validité du comportement de la méthode sous le test.

Donc, il est utile de voir les différentes méthodes de la classe Assert.

 

Assertion sur une seule valeur (Assertion on a single value)

  • Assert.AreEqual(object expected, object actual): Teste si les valeurs spécifiées sont égales. Différents types numériques sont traités comme inégaux même si les valeurs logiques sont égales. 42L n’est pas égal à 42.
  • Assert.AreNotEqual(object expected, object actual): Teste si les valeurs spécifiées sont inégales. Identique à AreEqual pour les valeurs numériques.
  • Assert.AreSame(object expected, object actual): Teste si les objets spécifiés font tous deux référence au même objet.
  • Assert.AreNotSame(object expected, object actual): Teste si les objets spécifiés font référence à différents objets
  • Assert.IsTrue(bool condition): Teste si la condition spécifiée est vraie
  • Assert.IsFalse(bool condition): Teste si la condition spécifiée est fausse
  • Assert.IsNull(object value): Teste si l’objet spécifié est nul
  • Assert.IsNotNull(object value): Teste si l’objet spécifié n’est pas nul
  • Assert.IsInstanceOfType(object value, Type type): Teste si l’objet spécifié est une instance du type attendu
  • Assert.IsNotInstanceOfType(object value, Type type): Teste si l’objet spécifié n’est pas une instance du mauvais type
  • StringAssert.Contains(string value, string substring): Teste si la chaîne spécifiée contient la sous-chaîne spécifiée
  • StringAssert.StartsWith(string value, string substring): Teste si la chaîne spécifiée commence par la sous-chaîne spécifiée
  • StringAssert.Matches(string value, Regex regex): Teste si la chaîne spécifiée correspond à une expression régulière
  • StringAssert.DoesNotMatch(string value, Regex regex): Teste si la chaîne spécifiée ne correspond pas à une expression régulière

 

Assertion sur les collections (Assertion on collections)

  • CollectionAssert.AreEqual(ICollection expected, ICollection actual): Teste si les collections spécifiées ont les mêmes éléments dans le même ordre et la même quantité.
  • CollectionAssert.AreNotEqual(ICollection expected, ICollection actual): Teste si les collections spécifiées n’ont pas les mêmes éléments ou si les éléments sont dans un ordre et une quantité différents.
  • CollectionAssert.AreEquivalent(ICollection expected, ICollection actual): Teste si deux collections contiennent les mêmes éléments.
  • CollectionAssert.AreNotEquivalent(ICollection expected, ICollection actual): Teste si deux collections contiennent des éléments différents.
  • CollectionAssert.AllItemsAreInstancesOfType(ICollection collection, Type expectedType): Teste si tous les éléments de la collection spécifiée sont des instances du type attendu
  • CollectionAssert.AllItemsAreNotNull(ICollection collection): Teste si tous les éléments de la collection spécifiée sont non nuls.
  • CollectionAssert.AllItemsAreUnique(ICollection collection): Teste si tous les éléments de la collection spécifiée sont uniques
  • CollectionAssert.Contains(ICollection collection, object element): Teste si la collection spécifiée contient l’élément spécifié
  • CollectionAssert.DoesNotContain(ICollection collection, object element): Teste si la collection spécifiée ne contient pas l’élément spécifié
  • CollectionAssert.IsSubsetOf(ICollection subset, ICollection superset): Teste si une collection est un sous-ensemble d’une autre collection
  • CollectionAssert.IsNotSubsetOf(ICollection subset, ICollection superset): Teste si une collection n’est pas un sous-ensemble d’une autre collection

 

Utilisation des tests de données

Dans le test unitaire effectué ci-dessus, nous avons testé la méthode TestAddOpertion une seule fois. Si nous voulons effectuer plusieurs tests afin de valider le comportement de la méthode Mathhelper.Add.

Le moyen le plus de simple est de faire un copier-coller de la méthode et puis on change les valeurs des paramètres.

Exemple

[TestClass]
public class MathTests
{
  [TestMethod]
  public void TestAddOpertion1()
  {
    int actuel = MathHelper.Add(1, 1);
    int attendu = 2;
    Assert.AreEqual(attendu, actuel);
  }

  [TestMethod]
  public void TestAddOpertion2()
  {
    int actuel = MathHelper.Add(2, 3);
    int attendu = 4;
    Assert.AreEqual(attendu, actuel);
  }
}

étant un développeur, vous pouvez éviter de faire un copier-coller du code, tout en utilisant les tests paramétriques.

 

L’attribut DataRow

L’attribut [DataRow] permet de fournir les valeurs des paramètres de test. Vous pouvez utiliser l’attribut [DataRow] autant que vous voulez afin de lancer N scenarios de test simultanément et de s’assurer le bon comportement de la méthode concernée.

Il faut souligner qu’il faut impérativement remplacer l’attribut [TestMethod] par [DataTestMethod].

Exemple

[TestClass]
public class MathTests
{
  [DataTestMethod]
  [DataRow(1, 1, 2)]
  [DataRow(12, 30, 42)]
  [DataRow(14, 1, 15)]
  public void TestAddOpertion(int a, int b, int attendu)
  {
    int actuel = MathHelper.Add(a, b);
    Assert.AreEqual(attendu, actuel);
  }
}

public class MathHelper
{
  public static int Add(int a, int b) => a + b;
}

 

Résultat

Vous pouvez constater qu’il y a 3 tests exécutés dans le test explorer

 

L’attribut DynamicData

Si votre jeu de donnée ne peut pas être dans les paramètres d’attribut (valeur inconstante, objet complexe), vous pouvez utiliser dans ce cas l’attribut [DynamicData]. Cet attribut permet la récupération des valeurs des paramètres provenant d’une méthode ou d’une propriété.

La méthode ou bien la propriété doit obligatoirement retourner IEnumerable<object[]>. Chaque ligne correspond aux valeurs de test.

Exemple

[TestClass]
public class MathTests
{
  [DataTestMethod]
  [DynamicData(nameof(GetData), DynamicDataSourceType.Method)]
  public void Test_Add_DynamicData_Method(int a, int b, int attendu)
  {
    var actuel = MathHelper.Add(a, b);
    Assert.AreEqual(attendu, actuel);
  }

  public static IEnumerable<object[]> GetData()
  {
    yield return new object[] { 1, 1, 2 };
    yield return new object[] { 12, 30, 42 };
    yield return new object[] { 14, 1, 15 };
  }
}

 

Résultat

 

Exemple avec des propriétés

[TestClass]
public class MathTests
{
  [DataTestMethod]
  [DynamicData(nameof(Data), DynamicDataSourceType.Property)]
  public void Test_Add_DynamicData_Property(int a, int b, int attendu)
  {
    var actuel = MathHelper.Add(a, b);
    Assert.AreEqual(attendu, actuel);
  }

  public static IEnumerable<object[]> Data
  {
    get
    {
      yield return new object[] { 1, 1, 2 };
      yield return new object[] { 12, 30, 42 };
      yield return new object[] { 14, 1, 15 };
    }
  }
}

 

Custom Data Source

Vous pouvez créer un attribut personnalisé. L’attribut doit implementer l’interface ITestDatasource. L’interface a deux methodes: GetData() et GetDisplayName().

GetData() : retourne les lignes de données(DataRow).

GetDisplayName() : retourne le nom de test pour une ligne de donnée. Ce nom est visible dans le test explorer.

Exemple

public class CustomDataSourceAttribute: Attribute, ITestDataSource
{
  public IEnumerable<object[]> GetData(MethodInfo methodInfo)
  {
    yield return new object[] { 1, 1, 2 };
    yield return new object[] { 12, 30, 42 };
    yield return new object[] { 14, 1, 15 };
  }

  public string GetDisplayName(MethodInfo methodInfo, object[] data)
  {
    if (data != null)
    return string.Format(CultureInfo.CurrentCulture, "Custom - {0} ({1})", methodInfo.Name, string.Join(",", data));
    return null;
  } }

 

Maintenant, nous pouvons utiliser l’attribut CustomDataSource comme tous les autres attributs.

Exemple

[TestClass]
public class MathTests
{
  [DataTestMethod]
  [CustomDataSource]
  public void TestAddOpertion1(int a, int b, int attendu)
  {
    int actuel = MathHelper.Add(a, b);
    Assert.AreEqual(attendu, actuel);
  }
}

 

Résultat

Les tests unitaires sont devenus une nécessité dans n’importe quel projet afin de s’assurer le comportement des développements réalisés. Dans cet article, j’ai essayé de partager avec vous la boite à outils de base qui va vous aider à réaliser les tests unitaires dans un projet .Net Core. Nous avons abordé le framework MSTest de Microsoft afin de couvrir les differentes parties de cet article. Ils existent d’autres framework intéressants peuvent être utilisés afin de réaliser les tests unitaires (ex: NUnit, XUnit etc..). 

Partager
Faire suivre