Utiliser Moq pour vérifier que les appels sont effectués dans le bon ordre

J’ai besoin de tester la méthode suivante:

CreateOutput(IWriter writer) { writer.Write(type); writer.Write(id); writer.Write(sender); // many more Write()s... } 

J’ai créé un Moq’d IWriter et je veux m’assurer que les méthodes Write() sont appelées dans le bon ordre.

J’ai le code de test suivant:

 var mockWriter = new Mock(MockBehavior.Ssortingct); var sequence = new MockSequence(); mockWriter.InSequence(sequence).Setup(x => x.Write(expectedType)); mockWriter.InSequence(sequence).Setup(x => x.Write(expectedId)); mockWriter.InSequence(sequence).Setup(x => x.Write(expectedSender)); 

Cependant, le deuxième appel à Write() dans CreateOutput() (pour écrire la valeur d’ id ) MockException une MockException avec le message ” L’invocation IWriter.Write () a échoué avec un comportement simulé ssortingct. “.

J’ai aussi du mal à trouver des documents / exemples définitifs de séquences Moq.

Est-ce que je fais quelque chose de mal ou est-ce que je ne peux pas mettre en place une séquence en utilisant la même méthode? Sinon, existe-t-il une alternative que je peux utiliser (de préférence en utilisant Moq / NUnit)?

Il y a un bug lors de l’ utilisation de MockSequence sur le même modèle . Il sera définitivement corrigé dans les versions ultérieures de la bibliothèque Moq (vous pouvez également le réparer manuellement en modifiant l’implémentation de Moq.MethodCall.Matches).

Si vous souhaitez utiliser uniquement Moq, vous pouvez vérifier l’ordre d’appel des méthodes via les rappels:

 int callOrder = 0; writerMock.Setup(x => x.Write(expectedType)).Callback(() => Assert.That(callOrder++, Is.EqualTo(0))); writerMock.Setup(x => x.Write(expectedId)).Callback(() => Assert.That(callOrder++, Is.EqualTo(1))); writerMock.Setup(x => x.Write(expectedSender)).Callback(() => Assert.That(callOrder++, Is.EqualTo(2))); 

J’ai réussi à obtenir le comportement que je souhaite, mais il faut télécharger une bibliothèque tierce à partir de http://dpwhelan.com/blog/software-development/moq-sequences/

La séquence peut ensuite être testée en utilisant les éléments suivants:

 var mockWriter = new Mock(MockBehavior.Ssortingct); using (Sequence.Create()) { mockWriter.Setup(x => x.Write(expectedType)).InSequence(); mockWriter.Setup(x => x.Write(expectedId)).InSequence(); mockWriter.Setup(x => x.Write(expectedSender)).InSequence(); } 

J’ai ajouté ceci comme réponse en partie pour aider à documenter cette solution, mais je m’intéresse toujours à savoir si quelque chose de similaire pourrait être réalisé avec Moq 4.0 seul.

Je ne suis pas sûr si Moq est encore en développement, mais corriger le problème avec MockSequence ou inclure l’extension moq-sequence dans Moq serait bien à voir.

J’ai écrit une méthode d’extension qui affirmera en fonction de l’ordre d’appel.

 public static class MockExtensions { public static void ExpectsInOrder(this Mock mock, params Expression>[] expressions) where T : class { // All closures have the same instance of sharedCallCount var sharedCallCount = 0; for (var i = 0; i < expressions.Length; i++) { // Each closure has it's own instance of expectedCallCount var expectedCallCount = i; mock.Setup(expressions[i]).Callback( () => { Assert.AreEqual(expectedCallCount, sharedCallCount); sharedCallCount++; }); } } } 

Cela fonctionne en tirant parti de la façon dont les fermetures fonctionnent par rapport aux variables de scope. Comme il n’y a qu’une seule déclaration pour sharedCallCount, toutes les fermetures auront une référence à la même variable. Avec expectedCallCount, une nouvelle instance est instanciée à chaque itération de la boucle (au lieu de simplement utiliser i dans la fermeture). De cette façon, chaque fermeture ne contient qu’une copie de i pour se comparer à sharedCallCount lorsque les expressions sont appelées.

Voici un petit test unitaire pour l’extension. Notez que cette méthode est appelée dans votre section d’installation, pas dans votre section d’assertion.

 [TestFixture] public class MockExtensionsTest { [TestCase] { // Setup var mock = new Mock(); mock.ExpectsInOrder( x => x.MyMethod("1"), x => x.MyMethod("2")); // Fake the object being called in order mock.Object.MyMethod("1"); mock.Object.MyMethod("2"); } [TestCase] { // Setup var mock = new Mock(); mock.ExpectsInOrder( x => x.MyMethod("1"), x => x.MyMethod("2")); // Fake the object being called out of order Assert.Throws(() => mock.Object.MyMethod("2")); } } public interface IAmAnInterface { void MyMethod(ssortingng param); } 

Récemment, j’ai réuni deux fonctionnalités pour Moq: VerifyInSequence () et VerifyNotInSequence (). Ils travaillent même avec des moquettes en vrac. Cependant, ceux-ci ne sont disponibles que dans un fork du référentiel moq:

https://github.com/grzesiek-galezowski/moq4

et attendez-vous à d’autres commentaires et tests avant de décider s’ils peuvent être inclus dans la version officielle de moq. Cependant, rien ne vous empêche de télécharger la source sous forme de fichier ZIP, de la comstackr en une DLL et de l’essayer. En utilisant ces fonctionnalités, la vérification de la séquence dont vous avez besoin pourrait être écrite en tant que telle:

 var mockWriter = new Mock  () {CallSequence = new LooseSequence ()};

 // effectue les appels nécessaires

 mockWriter.VerifyInSequence (x => x.Write (expectedType));
 mockWriter.VerifyInSequence (x => x.Write (expectedId));
 mockWriter.VerifyInSequence (x => x.Write (expectedSender));

(Notez que vous pouvez utiliser deux autres séquences, en fonction de vos besoins. La séquence lâche autorisera tous les appels entre ceux que vous voulez vérifier. SsortingctSequence ne le permet pas et SsortingctAnytimeSequence est comme SsortingctSequence (aucune méthode n’appelle entre les appels vérifiés) la séquence devant être précédée d’un nombre quelconque d’appels arbitraires.

Si vous décidez d’essayer cette fonctionnalité expérimentale, veuillez commenter sur: https://github.com/Moq/moq4/issues/21

Merci!

La solution la plus simple serait d’utiliser une queue :

 var expectedParameters = new Queue(new[]{expectedType,expectedId,expectedSender}); mockWriter.Setup(x => x.Write(expectedType)) .Callback((ssortingng s) => Assert.AreEqual(expectedParameters.Dequeue(), s)); 

Je soupçonne que attenduId n’est pas ce que vous attendez.

Cependant, je voudrais probablement écrire ma propre implémentation d’IWriter pour vérifier dans ce cas … probablement beaucoup plus facile (et plus facile à changer plus tard).

Désolé pour aucun conseil de Moq directement. Je l’aime, mais je ne l’ai pas fait avec ça.

avez-vous besoin d’append .Verify () à la fin de chaque configuration? (C’est vraiment une supposition, même si j’ai peur).