多个 MoqIt.Is < string >()匹配参数

对于 Moq,有多个匹配参数是否有效?

It.Is<string>()

在这个示例中,我希望知识库服务根据用户提供的信息返回一个不同的 ProviderUserKey。

mockMembershipService.Setup(
x => x.GetUser(
It.Is<string>(
s => s.Contains("Joe")))
.ProviderUserKey)
.Returns("1234abcd");




mockMembershipService.Setup(
x => x.GetUser(
It.Is<string>(
s => s.Contains("Tracy")))
.ProviderUserKey)
.Returns("5678efgh");

SetUp 默认使用第二个语句,而不是根据每个语句的优点进行评估。

109994 次浏览

Succesive Setup calls nullify previous setups.

You could use your argument in your return callback:

mockMembershipService.Setup(x => x.GetUser(It.IsAny<string>()).ProviderUserKey).Returns<string>(s =>
{
if(s.Contains("Joe"))
return "1234abcd";
else if(s.Contains("Tracy"))
return "5678efgh";
});

If it's important to you to assert the argument passed, you also need It.Is<string>(...) instead of It.IsAny<string>(...).

Isn't it confusing? You are trying to mock GetUser method but you set the Returns for that function's return value's property. You also want to state return type's property based on mocked method.

Here's a way a more clear way:

mockMembershipService.Setup(x => x.GetUser(It.IsAny<string>())
.Returns<string>(GetMembershipUser);

Here's a method to create the membership mock:

private MembershipUser GetMembershipUser(string s)
{
Mock<MembershipUser> user =new Mock<MembershipUser>();
user.Setup(item => item.ProviderUserKey).Returns(GetProperty(s));
return user.Object;
}

Then you write a method for setting that property:

private string GetProperty(string s)
{
if(s.Contains("Joe"))
return "1234abcd";
else if(s.Contains("Tracy"))
return "5678efgh";
}

If you want to restrict input to just "Joe" and "Tracy", you can specify multiple conditions in It.Is<T>(). Something like

mockMembershipService.Setup(x => x.GetUser(It.Is<String>(s => s.Contains("Joe")
|| s.Contains("Tracy")))
.Returns<string>(/* Either Bartosz's or Ufuk's answer */);

Please check Introduction to Moq > Matching Arguments documentation:

// matching Func<int>, lazy evaluated
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true);




// matching ranges
mock.Setup(foo => foo.Add(It.IsInRange<int>(0, 10, Range.Inclusive))).Returns(true);




// matching regex
mock.Setup(x => x.DoSomething(It.IsRegex("[a-d]+", RegexOptions.IgnoreCase))).Returns("foo");