web-dev-qa-db-fra.com

Comment configurer deux fois une méthode pour différents paramètres avec mock

Je voudrais installer une méthode avec Moq deux fois mais il semble que la dernière remplace les précédentes. Voici ma configuration initiale:

string username = "foo";
string password = "bar";

var principal = new GenericPrincipal(
    new GenericIdentity(username),
    new[] { "Admin" });

var membershipServiceMock = new Mock<IMembershipService>();
membershipServiceMock.Setup(ms =>
    ms.ValidateUser(username, password)
).Returns(new ValidUserContext { 
    Principal = principal
});

Cela fonctionne bien, mais je veux que ceci renvoie new ValidUserContext() si le nom d'utilisateur ou le mot de passe est plutôt que les variables username et password comme ci-dessus. Pour ce faire, j'ai ajouté une autre configuration mais cette fois, elle remplace celle ci-dessus et l'applique toujours:

membershipServiceMock.Setup(ms =>
    ms.ValidateUser(It.IsAny<string>(), It.IsAny<string>())
).Returns(
    new ValidUserContext()
);

Quelle est la manière la plus élégante de gérer ce type de situation avec Moq?

Modifier

J'ai résolu le problème avec l'approche ci-dessous mais je suppose qu'il existe un meilleur moyen de gérer cela:

var membershipServiceMock = new Mock<IMembershipService>();
membershipServiceMock.Setup(ms =>
    ms.ValidateUser(It.IsAny<string>(), It.IsAny<string>())
).Returns<string, string>((u, p) => 
    (u == username && p == password) ?
    new ValidUserContext { 
        Principal = principal
    }
    : new ValidUserContext()
);
28
tugberk

Moq supporte cela avec des contraintes d'argumentation:

mock.Setup(ms => ms.ValidateUser(
        It.Is<string>(u => u == username), It.Is<string>(p => p == password))
    .Returns(new ValidUserContext { Principal = principal });
mock.Setup(ms => ms.ValidateUser(
        It.Is<string>(u => u != username), It.Is<string>(p => p != password))
    .Returns(new ValidUserContext());

Catch-all It.IsAny fonctionne également, mais l'ordre est important:

// general constraint first so that it doesn't overwrite more specific ones
mock.Setup(ms => ms.ValidateUser(
        It.IsAny<string>(), It.IsAny<string>())
    .Returns(new ValidUserContext());
mock.Setup(ms => ms.ValidateUser(
        It.Is<string>(u => u == username), It.Is<string>(p => p == password))
    .Returns(new ValidUserContext { Principal = principal });
41
k.m

Une autre option immédiate consiste à utiliser la version de renvoi <> pour renvoyer différents ValidUserContexts en fonction des paramètres. Ce n'est pas mieux que la réponse ci-dessus, juste une autre option.

Nous avons configuré ValidateUser () pour renvoyer le résultat d'une fonction GetUserContext (chaîne, chaîne), en transmettant le nom d'utilisateur et le mot de passe avec lesquels ValidateUser () a été appelé.

[TestClass]
public class MultipleReturnValues {

    public class ValidUserContext {
        public string Principal { get; set; }
    }

    public interface IMembershipService {
        ValidUserContext ValidateUser(string name, string password);
    }

    [TestMethod]
    public void DifferentPricipals() {

        var mock = new Mock<IMembershipService>();
        mock.Setup(mk => mk.ValidateUser(It.IsAny<string>(), It.IsAny<string>())).Returns<string, string>(GetUserContext);

        var validUserContext = mock.Object.ValidateUser("abc", "cde");

        Assert.IsNull(validUserContext.Principal);


        validUserContext = mock.Object.ValidateUser("foo", "bar");

        Assert.AreEqual(sPrincipal, validUserContext.Principal);


    }

    private static string sPrincipal = "A Principal";
    private static ValidUserContext GetUserContext(string name, string password) {

        var ret = new ValidUserContext();

        if (name == "foo" && password == "bar") {
            ret = new ValidUserContext { Principal = sPrincipal };
        }
        return ret;

    }
}
3
AlanT

Si vous regardez la définition de fonction pour Setup():  enter image description here Tout ce que vous avez à faire est de commuter la Commande de deux appels Setup():

membershipServiceMock.Setup(ms =>
    ms.ValidateUser(It.IsAny<string>(), It.IsAny<string>())
).Returns(
    new ValidUserContext()
);
membershipServiceMock.Setup(ms =>
    ms.ValidateUser(username, password)
).Returns(new ValidUserContext { 
    Principal = principal
});

donc, si l'entrée est bien username et password, les deux appels Setup() sont qualifiés mais gagnent plus tard en raison de la règle et lorsque vous avez d'autres entrées, seul le premier est apparié et appliqué 

0
watashiSHUN