.Net

Mocking avec Moq

Jan 7, 2015

Idir BOURKEB

MoqLogo

Généralement, nous sommes confrontés à gérer plusieurs dépendances externes pendant la phase de développement ou de test : une base de données, un service WCF ou bien un fichier XML. Dans ce cas, il est difficile de coder ou tester l’application sans coder en dur ces dépendances surtout si nous n’avons pas l’implémentation que ce soit parce que ces dépendances ne sont pas encore codées ou bien nous n’avons que des contrats.

Mocking ?

Selon Wikipedia, les mocks sont des objets simulés qui reproduisent le comportement des objets réels de manière contrôlée. Un programmeur crée un mock dans le but de tester le comportement d’autres objets, réels, mais liés à un objet inaccessible ou non implémenté. Ce dernier est alors remplacé par un mock.

En bref, les mocks sont un excellent moyen pour simuler un objet que nous devons travailler avec. Parfois, nous pouvons également rencontrer des situations difficiles à reproduire. Disons, par exemple, nous devons simuler une erreur de réseau ou une erreur spécifique dans notre base de données, avec un mocking framework nous pouvons le faire facilement.

Un autre avantage de l’utilisation d’un mocking framework est que les resources externes utilisées ne seront pas affectées : nous pouvons simuler un appel de base de données qui ne l’affectera pas. Vous pouvez également mocker du code qui n’existe pas.

Mocking, Stubbing ?

En bref, je crois que la plus grande différence est que le stub possède déjà un comportement prédéterminé. Tandis que pour un Mock, la configuration du comportement est codée dans le test.

Pourquoi utiliser les Mocks ?

Lors de l’écriture des tests unitaires, nous avons besoin d’écrire des tests qui couvrent une partie de code spécifique. Le code sous test ou la classe sous test (Code/Class Under Test (CUT)) peut interagir avec d’autres classes ou des systèmes externes. L’utilisation des Mocks nous permettra d’isoler la classe que nous travaillons avec et donc de faciliter l’écriture des tests.

Pour cet article, je vais utiliser le framework Moq puisqu’il est vraiment facile à utiliser et il est le plus populaire dans les Mocking Framework .Net .Celà dit, il y a des tas d’autres Mocking Framework (NSubstitute, RhinoMocks, FakeItEasy….) https://nugetmusthaves.com/Tag/mocking .

Installation

 Il existe 2 manières pour installer Moq :

  1. Avec le plugin Nuget dans Visual Studio en téléchargeant « Moq ».
  2. Manuellement : il suffit de télécharger la DLL sur le site officiel https://code.google.com/p/moq/ et la référencer dans votre projet.

Implementation

Moq est un framework open source qui suit le style arrange-act-assert et s’appuie fortement sur les lambdas expressions et les méthodes d’extension.

Le code suivant sera notre code de base qui sera testé:

public class MessageService : IMessageService
{
  private readonly IRepository<Message> _messageRepo;
        
  public MessageService(IRepository<Message> messageRepo)
  {
     _messageRepo = messageRepo;
  }

  public Message Find(int? id)
  {
    if (id.HasValue)
    {
       return _messageRepo.Find(id);
    }
    return null;
  }
}

Nous avons un MessageService  qui a une dépendance IRepository<Message>  agissant comme une interface à une classe qui, dans notre cas, va retourner les données à partir d’une base de données. J’ai omis la mise en œuvre de cette interface parce que cela va être un objet que nous allons moquer : nous ne voulons pas vraiment aller à la base de données et récupérer des données.

Avec notre premier test, nous allons créer un Mock qui représente IRepository<Message>  et met en place les attentes (expectations). Une attente pourrait représenter deux choses: ce que la méthode devrait recevoir comme paramètres d’entrée, et ce que la méthode devrait retourner comme résultat.

[TestMethod]
public void GetMessage_ValidId()
{
  // 1. Arrange ----------------------
  const int message_ID = 1;
  const int message_Subscriber_ID = 1;
  const string text = "Message to test";
 
  // Création d'un faux IRepository<Message>
  var repository = new Mock<IRepository<Message>>();
 
  // Mise en place du référentiel pour renvoyer exactement ce que nous attendons
  repository.Setup(m => m.Find(message_ID))
            .Returns(new Message { Message_Subscriber_ID = message_Subscriber_ID, Text = text });
 
  var service = new MessageService(repository.Object);
 
  // 2. Act ----------------------
  var message = service.Find(message_ID);
 
  // 3. Assert  ----------------------
  Assert.IsTrue(message != null);
  Assert.IsTrue(message.Message_Subscriber_ID == message_Subscriber_ID);
  Assert.IsTrue(message.Text == text);
}

Une petite explication s’impose:

var repository = new Mock<IRepository<Message>>();

 

Cette instruction crée un nouvel objet qui implémente toutes les méthodes et propriétés de l’interface IRepository<Message>.

repository.Setup(m => m.Find(message_ID))
          .Returns(new Message { Message_Subscriber_ID = message_Subscriber_ID, Text = text });

Le code ci-dessus fait deux choses:

  1. La méthode Setup définit ce que nous voulons tester et le paramètre d’entrée attendu. Dans notre cas, le test échouera si le paramètre d’entrée ne sera pas égal à ce que nous avons défini dans la configuration. Le paramètre d’entrée doit être égal à message_ID.Il y a une possibilité d’utiliser ainsi It.IsAny () de dire que nous ne nous soucions pas vraiment ce que le paramètre d’entrée contient, mais il doit être de type int.
  2. La méthode Returns définit le résultat, ce qui est retourné à l’exécution du test.

Après l’exécution de la méthode Setup, Moq génère un objet similaire à ce qui suit :

public class MoqClassName : IRepository<Message>
{
   public Message Find(int id)
    {
        return new Message
                { 
                    Message_Subscriber_ID = 1, 
                    Text = "Message to test"
                }
    }
}

Comme vous voyez, la classe implémente l’interface IRepository<Message> et contient certaines valeurs « codées en dur » qui seront retournées.

Dans cet article, j’ai mentionné le plus simple des tests, mais il y a un certain nombre d’autres techniques qui pourront être utilisées. N’hésitez pas à tester!

0 commentaires

Soumettre un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Découvrez nos autres articles

Aller au contenu principal