web-dev-qa-db-de.com

Wie man eine Methode zweimal für verschiedene Parameter mit Mock einrichtet

Ich würde gerne eine Methode mit Moq zweimal einrichten, aber es scheint, als ob die letzte die vorherigen überschreibt. Hier ist mein erstes Setup:

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
});

Das klappt gut, aber ich möchte new ValidUserContext() zurückgeben, wenn der Benutzername oder das Passwort anstelle der Variablen username und password wie oben angegeben ist. Um dies zu tun, habe ich ein anderes Setup hinzugefügt, aber dieses Mal überschreibt es das oben genannte und wendet es immer an:

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

Was ist die eleganteste Art und Weise, mit dieser Art von Situationen mit Moq umzugehen?

Bearbeiten

Ich habe das Problem mit dem folgenden Ansatz gelöst, aber ich denke, es gibt einen besseren Weg, dies zu handhaben:

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 unterstützt dies sofort mit Argumenteinschränkungen:

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 funktioniert auch, aber die Reihenfolge ist wichtig:

// 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

Eine andere Option ist die Verwendung der Return <> -Version, um abhängig von den Parametern andere ValidUserContexts zurückzugeben. Es ist nicht besser als die obige Antwort, nur eine weitere Option.

Wir richten ValidateUser () so ein, dass das Ergebnis einer Funktion GetUserContext (string, string) zurückgegeben wird, wobei der Benutzername und das Kennwort übergeben werden, mit denen ValidateUser () aufgerufen wurde.

[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

Wenn Sie die Funktionsdefinition für Setup() betrachten:  enter image description here Sie müssen lediglich die Order von zwei Setup()-Aufrufen wechseln:

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
});

wenn also die Eingabe tatsächlich username und password ist, sind beide Setup()-Aufrufe qualifiziert, gewinnen jedoch später aufgrund der Regel und wenn Sie weitere Eingaben haben, wird nur die erste Übereinstimmung gefunden und angewendet 

0
watashiSHUN