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


76

使用Moq,拥有多个匹配参数是否有效?

It.Is<string>() 

在此示例中,我希望mockMembershipService返回一个不同的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默认为第二条语句,而不是根据各自的价值进行评估。

Answers:


54

是不是很混乱?您正在尝试模拟GetUser方法,但是您为该函数的返回值属性设置了Returns。您还希望根据模拟方法声明返回类型的属性。

这是一种更清晰的方法:

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

这是创建成员资格模拟的方法:

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

然后,编写一种用于设置该属性的方法:

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

1
请稍后尝试一下,正在观看这段视频thethoughtfulcoder.com/blog/52/…,同时您添加了类似的答案
Nicholas Murray

上面的代码无法编译,它抱怨Security.MembershipUser不包含返回引用,也不包含不包含ProviderUserKey定义的用户
Nicholas Murray

我猜应该引用包含Security.MembershipUser的程序集。或者,您可以在MembershipService中注入依赖关系来为您创建用户
UfukHacıoğulları2012年

嗯-当我尝试自己的方式时,它不会抱怨-(这当然不会像脱机那样工作)
Nicholas Murray

我猜您可以编写另一个函数来创建MembershipUser模拟,但是它已经严重失控了。我更新了代码。
UfukHacıoğulları2012年

33

如果要将输入限制为仅“ Joe”和“ Tracy”,则可以在中指定多个条件It.Is<T>()。就像是

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

它不是我想限制本身,我只是想评估什么输入并返回所需的输出:-)
Nicholas Murray

不管这个位置是否正确,都对我有所帮助,谢谢@ cadrell0
Jacob McKay

15

成功的安装程序调用会使以前的设置无效。

您可以在return回调中使用参数:

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

如果断言传递的参数对您很重要,则也需要It.Is<string>(...)而不是It.IsAny<string>(...)


我应该在大约2个小时内尝试一下。
Nicholas Murray

嗯,我认为这是因为我们要在此处(ProviderUserKey)设置属性,而我们要根据其作用的参数来自GetUser(...)。目前无法检查正确的解决方案,但是如果您遵循Ufuk的建议,那应该没问题...
Bartosz 2012年

周末我会试一试-感谢您的帮助!不像我最初想到的那样直接。
尼古拉斯·默里

@mattumotu:那不是我所经历的,Moq只是有一个奇怪的执行策略。以后添加的安装程序调用将首先评估(或始终评估所有评估,最后获胜)。这与预期的相反:通常会返回第一个匹配项,而其余匹配项将被忽略。
Christoph

6

请查看Moq简介>匹配参数文档:

// 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");

3
现在,由于拥有更多的单元测试经验,因此不建议您使用这种方法。我们应该避免将逻辑放在单元测试中。另一种选择是创建单独的单元测试:一个用于Joe,另一个用于Tracy
Jaider
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.