Création des tests unitaires pour la couche de serviceNous allons maintenant créer un jeu de tests unitaires pour la couche de service de l’application de gestion de contacts. Nous utiliserons ces tests afin de vérifier notre logique de validation. 1. Créez un nouveau répertoire « Models » dans le projet « ContactManager.Tests ». Puis cliquez droit sur ce répertoire et sélectionnez « Add, New Test ». .jpg)
1. Sélectionnez le template « Unit Test » et donnez lui comme nom : « ContactManagerServiceTest.cs » puis cliquez « Ok » En général, on fait correspondre le projet de tests avec la structure du projet ASP.NET MVC. Par exemple, on mettra le test du contrôleur dans un répertoire « Controller », le test du modèle dans un répertoire « Model » etc… Pour commencer, on va tester la méthode CreateContact() de la classe ContactManagerService. Nous allons donc créer ces 5 tests : 1. CreateContact() - Test si CreateContact() retourne la valeur vrai quand un contact « valide » est passé à la méthode. 2. CreateContactRequiredFirstName() – Test si un message d’erreur est généré quand on envoi un Contact sans la propriété « FirstName » remplie (prénom) à la méthode CreateContact() 3. CreateContactRequredLastName() – Test si un message d’erreur est généré quand on envoi un Contact sans la propriété « LastName » remplie (nom de famille) à la méthode CreateContact() 4. CreateContactInvalidPhone() – Test si un message d’erreur est généré quand on envoi un Contact avec un numéro de téléphone non valide à la méthode CreateContact() 5. CreateContactInvalidEmail() – Test si un message d’erreur est généré quand on envoi un Contact avec une adresse email non valide à la méthode CreateContact() Le premier test vérifie qu’un contact valide ne génère pas de messages d’erreur. Les tests suivant vérifient chaque règle de saisie. Code des tests dans le Source 1. Listing 1 – Models\ContactManagerServiceTest.cs using System.Web.Mvc; using ContactManager.Models; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq;
namespace ContactManager.Tests.Models { [TestClass] public class ContactManagerServiceTest { private Mock>IContactManagerRepository< _mockRepository; private ModelStateDictionary _modelState; private IContactManagerService _service;
[TestInitialize] public void Initialize() { _mockRepository = new Mock>IContactManagerRepository<(); _modelState = new ModelStateDictionary(); _service = new ContactManagerService(new ModelStateWrapper(_modelState), _mockRepository.Object); }
[TestMethod] public void CreateContact() { // Arrange var contact = Contact.CreateContact(-1, "Stephen", "Walther", "555-5555", "steve@somewhere.com");
// Act var result = _service.CreateContact(contact); // Assert Assert.IsTrue(result); }
[TestMethod] public void CreateContactRequiredFirstName() { // Arrange var contact = Contact.CreateContact(-1, string.Empty, "Walther", "555-5555", "steve@somewhere.com");
// Act var result = _service.CreateContact(contact);
// Assert Assert.IsFalse(result); var error = _modelState["FirstName"].Errors[0]; Assert.AreEqual("First name is required.", error.ErrorMessage); }
[TestMethod] public void CreateContactRequiredLastName() { // Arrange var contact = Contact.CreateContact(-1, "Stephen", string.Empty, "555-5555", "steve@somewhere.com");
// Act var result = _service.CreateContact(contact);
// Assert Assert.IsFalse(result); var error = _modelState["LastName"].Errors[0]; Assert.AreEqual("Last name is required.", error.ErrorMessage); }
[TestMethod] public void CreateContactInvalidPhone() { // Arrange var contact = Contact.CreateContact(-1, "Stephen", "Walther", "apple", "steve@somewhere.com");
// Act var result = _service.CreateContact(contact);
// Assert Assert.IsFalse(result); var error = _modelState["Phone"].Errors[0]; Assert.AreEqual("Invalid phone number.", error.ErrorMessage); }
[TestMethod] public void CreateContactInvalidEmail() { // Arrange var contact = Contact.CreateContact(-1, "Stephen", "Walther", "555-5555", "apple");
// Act var result = _service.CreateContact(contact);
// Assert Assert.IsFalse(result); var error = _modelState["Email"].Errors[0]; Assert.AreEqual("Invalid email address.", error.ErrorMessage); } } }
Comme on utilise la classe Contact dans ce code source, on doit ajouter une référence au Framework « Microsoft Entity ». Ajoutez donc une référence à l’assembly System.Data.Entity. Le code du Listing 1 contient une méthode « Initialize() » auquel on a ajouté un attribut [TestInitialize]. Cette méthode sera donc appelée automatiquement avant chaque test unitaire (ici elle sera appelée 5 fois, 1 fois par test unitaire). La méthode Initialize() créé une couche de simulation de l’accès aux données grâce à cette ligne de code :
_mockRepository = new Mock>IContactManagerRepository<();
Cette ligne de code utilise le Framework « Moq » pour générer un accès aux données virtuel et ceci depuis l’interface IContactManagerRepository. La « fausse » couche d’accès aux données sera utilisée plutôt que celle de type « EntityContactManagerRepository » qui aurait besoin de faire un accès physique à la base chaque fois. La « fausse » couche d’accès aux données implémente l’interface IContactManagerRepository, mais les méthodes ne font rien. Quand on utilise le framework « Moq », il y a une distinction à faire entre _mockRepository et _mockRepository.Object. Le premier fait référence à la classe Mock<IContactManagerRepository> qui contient les méthodes pour spécifier le comportement de la « fausse » classe. Tant dis que l’autre implémente simplement l’interface IContactManagerRepository. La « fausse » couche d’accès aux données utilise la méthode Initialize() quand une instance de la classe ContactManagerService est créé. Tous les tests unitaires utilisent cette instance de la classe ContactManagerService. Le code du Listing 1 contient 5 méthodes. Chacune correspond à un test unitaire. Chaque méthode est décorée de l’attribut [TestMethod]. Quand les tests unitaires sont lancés, chaque méthode décorée de cet attribut est appelée. En d’autres termes, chaque méthode qui est décorée de cet attribut [TestMethod] devient un test unitaire. Le premier test unitaire, nommé CreateContact(), vérifie que l’appel à CreateContact() retourne la valeur « vrai » dans le cas où on lui passe un contact « valide ». Les autres tests vérifient que la méthode CreateContact() renvoie faux quand on lui passe un Contact qui n’est pas valide et qu’une exception est bien est soulevée. Par exemple, le test CreateContactRequiredFirstName() s’occupe de tester la création de la classe Contact avec une chaine vide dans la propriété FirstName. Ensuite, il appelle la méthode CreateContact() avec ce Contact non valide. Finalement, le test vérifie bien que la méthode CreateContact() renvoie « faux » et que le modèle lève une exception en conséquence avec comme message « First Name is required » Vous pouvez lancer le test du code Listing 1 en allant dans le menu « Test / Run / All Tests in Solution » ou (CTRL+R, A). Le résultat des tests doit s’afficher comme ceci (Figure 4): .jpg)
Figure 04: Résultat des tests. |