108 votes

Utiliser Moq pour se moquer uniquement de certaines méthodes

J'ai la méthode suivante:

public CustomObect MyMethod()
{
    var lUser = GetCurrentUser();
    if (lUser.HaveAccess)
    {
        //Un comportement
    }
    else 
    {
        //Autre comportement
    }

    //retourner CustomObject
}

Je veux simuler IMyInterface.GetCurrentUser, de sorte que lors de l'appel à MyMethod, je puisse accéder à l'un des parcours de code pour le vérifier. Comment faire cela avec Moq?

Je fais la chose suivante:

var moq = new Mock();
moq.Setup(x => x.GetCurrentUser()).Returns(lUnauthorizedUser);

//agir
var lResult = moq.Object.MyMethod();

Mais pour une raison quelconque, lResult est toujours null, et lorsque j'essaie d'entrer dans MyMethod en mode debug, je passe toujours à l'instruction suivante.

199voto

lee Points 353

Cela s'appelle un faux partiel, et la façon que je connais de le faire dans Moq nécessite de se moquer de la classe plutôt que de l'interface, puis de définir la propriété CallBase sur votre objet moqué à true.

Cela nécessitera de rendre toutes les méthodes et propriétés de la classe que vous testez virtuelles. En supposant que ce n'est pas un problème, vous pouvez ensuite écrire un test comme ceci :

var mock = new Mock();
mock.CallBase = true;
mock.Setup(x => x.GetCurrentUser()).Returns(lUnauthorizedUser);
mockedTest.Object.MyMethod();

55voto

Brandon Rader Points 378

J'ai eu un cas similaire. J'ai trouvé que le code suivant me donnait plus de flexibilité pour utiliser à la fois des méthodes simulées et des méthodes réelles d'une implémentation spécifique d'une interface :

var mock = new Mock(); // Créer un Mock de l'interface

// Créer une instance de l'implémentation de ITestClass que vous souhaitez utiliser
var inst = new ActualTestClass();

// Configuration pour appeler une méthode d'une instance réelle 
// si la méthode renvoie void, utilisez mock.Setup(...).Callback(...)
mock.Setup(m => m.SomeMethod(It.IsAny())
    .Returns((int x) => inst.SomeMethod(x));

Maintenant, vous pouvez utiliser la méthode réelle mais aussi utiliser des choses comme Verify pour voir combien de fois elle a été appelée.

54voto

Charles W Points 1944

En développant la réponse de lee,

Vous n'avez pas besoin de rendre toutes les méthodes et propriétés de votre classe virtuelles, seulement celles que vous souhaitez simuler.

De plus, il convient de noter que vous devriez simuler l'implémentation concrète de votre classe.

var mock = new Mock(); // vs. var mock = new Mock();

Si votre classe n'a pas de constructeur par défaut, vous devrez également spécifier les arguments à lui transmettre via :

var mock = new Mock(x, y, z);
// ou
var mock = new Mock(MockBehavior.Default, x, y, z);

x, y, z sont respectivement le premier, deuxième et troisième paramètre de votre constructeur.

Et enfin, si la méthode que vous souhaitez simuler est protégée, vous devrez inclure Moq.Protected

using Moq.Protected;

TypeDeRetour returnValue = default(TypeDeRetour);

mock.Protected()
    .Setup("VotreNomDeMock", It.IsAny()) // nom de la méthode suivi des arguments
    .Returns(returnValue);

14voto

Kyle Cooley Points 43

Étant donné que c'était un résultat de premier plan lors de la recherche, en complément de la réponse de Lee, vous pouvez éviter d'utiliser des méthodes virtuelles en utilisant la méthode As() pour assigner une interface.

var mock = new Mock().As();
mock.CallBase = true;

var vraiResultat = mock.Object.VotreMéthode();

mock.Setup(c => c.VotreMéthode()).Returns("FAUX");

var fauxResultat = mock.Object.VotreMéthode();

Cependant, notez que si votre classe utilise internalement une méthode que vous simulez de cette manière, elle appellera toujours la vraie méthode car elle n'a pas connaissance du type simulé et appelle à partir de this. Cela réduit la facilité d'utilisation de cette approche et peut vous conduire (comme moi) à comprendre pourquoi il y a peu de documentation sur ce schéma.

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