web-dev-qa-db-fra.com

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)
    {
        //One behavior
    }
    else 
    {
        //Other behavior
    }

    //return CustomObject
}

Je veux me moquer IMyInterface.GetCurrentUser, afin qu'en appelant MyMethod je puisse accéder à l'un des chemins de code pour le vérifier. Comment faire ça avec Moq?

Je fais la chose suivante:

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

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

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

58
Yaroslav Yakovlev

Cela s'appelle une simulation partielle et la façon dont je sais 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" de votre objet simulé sur "true".

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

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

Développer sur réponse de Lee ,

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

En outre, il convient de noter que vous devez vous moquer de l'implémentation concrète de votre classe.

var mock = new Mock<YourTestClass>(); // vs. var mock = new Mock<IYourTestInterface>();

Si votre classe n'a pas de constructeur par défaut, vous devrez également spécifier des arguments pour lui passer via:

var mock = new Mock<YourTestClass>(x, y, z);
// or
var mock = new Mock<YourTestClass>(MockBehavior.Default, x, y, z);

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

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

using Moq.Protected;

TReturnType returnValue = default(TReturnType);

mock.Protected()
    .Setup<TReturnType>("YourMockMethodName", It.IsAny<int>()) // methodname followed by arguments
    .Returns(returnValue);
22
Charles W

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

var mock = new Mock<ITestClass>(); // Create Mock of interface

// Create instance of ITestClass implementation you want to use
var inst = new ActualTestClass();

// Setup to call method of an actual instance
// if method returns void use mock.Setup(...).Callback(...)
mock.Setup(m => m.SomeMethod(It.IsAny<int>())
    .Returns((int x) => inst.SomeMethod(x));

Vous pouvez maintenant utiliser la méthode actuelle mais aussi utiliser des choses comme Verify pour voir combien de fois elle a été appelée.

16
Brandon Rader