C# 如何用最小起订量对不同参数设置两次方法

C# 如何用最小起订量对不同参数设置两次方法,c#,.net,unit-testing,moq,C#,.net,Unit Testing,Moq,我想用最小起订量设置一个方法两次,但似乎最后一次覆盖了以前的方法。以下是我的初始设置: string username = "foo"; string password = "bar"; var principal = new GenericPrincipal( new GenericIdentity(username), new[] { "Admin" }); var membershipServiceMock = new Mock<IMembershipServic

我想用最小起订量设置一个方法两次,但似乎最后一次覆盖了以前的方法。以下是我的初始设置:

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
});
用最小起订量处理这种情况最优雅的方法是什么

编辑

我用以下方法解决了这个问题,但我想有更好的方法来处理这个问题:

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()
);
var membershipServiceMock=new Mock();
membershipServiceMock.Setup(ms=>
ms.ValidateUser(It.IsAny(),It.IsAny())
).返回((u,p)=>
(u==用户名和p==密码)?
新ValidUserContext{
本金=本金
}
:新建ValidUserContext()
);

Moq支持这种开箱即用的参数约束:

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

另一个现成的选项是使用返回版本根据参数返回不同的ValidUserContext。这并不比上面的答案好,只是另一个选择

我们设置ValidateUser()以返回函数GetUserContext(string,string)的结果,传入调用ValidateUser()的用户名和密码

[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;

    }
}
[TestClass]
公共类多重返回值{
公共类ValidUserContext{
公共字符串主体{get;set;}
}
公共接口IMembershipService{
ValidUserContext ValidateUser(字符串名称、字符串密码);
}
[测试方法]
public void differentitpricipals(){
var mock=new mock();
mock.Setup(mk=>mk.ValidateUser(It.IsAny(),It.IsAny()).Returns(GetUserContext);
var validUserContext=mock.Object.ValidateUser(“abc”、“cde”);
IsNull(validUserContext.Principal);
validUserContext=mock.Object.ValidateUser(“foo”、“bar”);
AreEqual(sPrincipal、validUserContext.Principal);
}
私有静态字符串sPrincipal=“主体”;
私有静态ValidUserContext GetUserContext(字符串名称、字符串密码){
var ret=新的ValidUserContext();
如果(名称==“foo”&&password==“bar”){
ret=新的ValidUserContext{Principal=sPrincipal};
}
返回ret;
}
}

如果查看
Setup()
的函数定义:


因此,如果输入确实是
username
password
,则两个
Setup()
调用都是合格的,但由于该规则,后一个调用获胜,并且当您有任何其他输入时,只有第一个输入匹配并应用。

第一个解决方案不处理u==username和p!=密码,还是密码?
// 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 });
[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;

    }
}
// Remarks:
//     If more than one setup is specified for the same method or property, the latest
//     one wins and is the one that will be executed.
public ISetup<T, TResult> Setup<TResult>(Expression<Func<T, TResult>> expression);
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
});