64 votes

Moq, utilisation stricte ou libre

Dans le passé, je n'ai utilisé que Rhino Mocks, avec le mock strict typique. Je travaille maintenant avec Moq sur un projet et je m'interroge sur l'utilisation appropriée.

Supposons que j'ai un objet Foo avec une méthode Bar qui appelle une méthode Bizz sur l'objet Buzz.

Dans mon test, je veux vérifier que Bizz est appelé, donc je pense qu'il y a deux options possibles :

Avec une stricte moquerie

var mockBuzz= new Mock<IBuzz>(MockBehavior.Strict);
mockBuzz.Setup(x => x.Bizz()); //test will fail if Bizz method not called
foo.Buzz = mockBuzz
foo.Bar();
mockBuzz.VerifyAll();

Avec un simulacre libre

var mockBuzz= new Mock<IBuzz>();    
foo.Buzz = mockBuzz
foo.Bar();
mockBuzz.Verify(x => x.Bizz()) //test will fail if Bizz method not called

Existe-t-il une manière standard ou normale de procéder ?

87voto

Andy Lowry Points 847

J'avais l'habitude d'utiliser des mocks stricts lorsque j'ai commencé à utiliser des mocks dans les tests unitaires. Cela n'a pas duré très longtemps. Il y a vraiment 2 raisons pour lesquelles j'ai arrêté de le faire :

  1. Les tests deviennent fragiles - Avec les mocks stricts, vous affirmez plus d'une chose, que les méthodes de configuration sont appelées, ET que les autres méthodes ne sont pas appelées. Lorsque vous remaniez le code, le test échoue souvent, même si ce que vous essayez de tester est toujours vrai.
  2. Les tests sont plus difficiles à lire - Vous devez avoir une configuration pour chaque méthode qui est appelée sur le mock, même si elle n'est pas vraiment liée à ce que vous voulez tester. Lorsque quelqu'un lit ce test, il lui est difficile de dire ce qui est important pour le test et ce qui est juste un effet secondaire de l'implémentation.

Pour ces raisons, je recommande fortement d'utiliser des mocks libres dans vos tests unitaires.

40voto

Benedict Points 1228

J'ai une expérience du développement C++/non-.NET et je me suis récemment intéressé à .NET. J'avais donc certaines attentes lorsque j'ai utilisé Moq pour la première fois. J'essayais de comprendre ce qui se passait avec mon test et pourquoi le code que je testais lançait une exception aléatoire au lieu que la bibliothèque Mock me dise quelle fonction le code essayait d'appeler. J'ai donc découvert que j'avais besoin d'activer le comportement Strict, ce qui m'a laissé perplexe - et puis je suis tombé sur cette question qui n'avait pas encore de réponse cochée.

En Loose et le fait qu'il s'agisse du mode par défaut. est fou . Quel est l'intérêt d'une bibliothèque Mock qui fait quelque chose de complètement imprévisible que vous n'avez pas explicitement listé comme devant être fait ?

Je ne suis absolument pas d'accord avec les points énumérés dans les autres réponses à l'appui du mode Loose. Il n'y a aucune bonne raison de l'utiliser et je ne le voudrais jamais, jamais. Lorsque j'écris un test unitaire, je veux être certain de ce qui se passe - si je sais qu'une fonction doit retourner un null, je lui ferai retourner ce null. Je veux que mes tests soient fragiles (dans les aspects qui comptent) afin que je puisse les corriger et ajouter à la suite de code de test les lignes de configuration qui sont les informations explicites qui me décrivent exactement ce que mon logiciel va faire.

La question est la suivante : existe-t-il une manière standard et normale de procéder ?

Oui - du point de vue de la programmation en général, c'est-à-dire des autres langages et en dehors du monde .NET, vous devriez toujours utiliser Strict. Dieu seul sait pourquoi ce n'est pas la valeur par défaut dans Moq.

11voto

Amol Points 361

J'ai une convention simple :

  1. Utilisez des objets fantaisie stricts lorsque le système en cours de test (SUT) délègue l'appel à la couche fantaisie sous-jacente sans réellement modifier ou appliquer une quelconque logique commerciale aux arguments qui lui sont passés.

  2. Utilisez des simulateurs libres lorsque le SUT applique une logique d'entreprise aux arguments qui lui sont transmis et transmet certaines valeurs dérivées/modifiées à la couche simulée.

Par exemple Disons que nous avons un fournisseur de base de données StudentDAL qui a deux méthodes :

L'interface d'accès aux données ressemble à ce qui suit :

public Student GetStudentById(int id);
public IList<Student> GetStudents(int ageFilter, int classId);

L'implémentation qui consomme ce DAL ressemble à ce qui suit :

public Student FindStudent(int id)
{
   //StudentDAL dependency injected
   return StudentDAL.GetStudentById(id);
   //Use strict mock to test this
}
public IList<Student> GetStudentsForClass(StudentListRequest studentListRequest)
{
  //StudentDAL dependency injected
  //age filter is derived from the request and then passed on to the underlying layer
  int ageFilter = DateTime.Now.Year - studentListRequest.DateOfBirthFilter.Year;
  return StudentDAL.GetStudents(ageFilter , studentListRequest.ClassId)
  //Use loose mock and use verify api of MOQ to make sure that the age filter is correctly passed on.

}

5voto

mithun_daa Points 1375

Personnellement, étant novice en matière de moquerie et de Moq, je pense que commencer par le mode Strict permet de mieux comprendre les rouages et ce qui se passe. Le mode "Loose" permet parfois de cacher des détails et de faire passer un test qu'un débutant en Moq pourrait ne pas voir. Une fois que vous aurez acquis des compétences en matière de mocking, le mode "Loose" sera probablement beaucoup plus productif, comme dans le cas présent où vous économisez une ligne avec le "Setup" et où vous utilisez simplement "Verify" à la place.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X