简体   繁体   English

我如何使用It.IsAny作为参数?

[英]How can I use It.IsAny as a parameter?

I have a test class invoking a mock of MyClass , I've Setup both DoStuffA and DoStuffB previously. 我有一个测试类调用MyClass的模拟,我之前SetupDoStuffADoStuffB

I've tried to wrap several Verify calls within a method, like so: 我试图在一个方法中包装几个Verify调用,如下所示:

void VerifyMany(int input)
{
    _myClassMock.Verify(ic => ic.DoStuffA(input), Times.Once());
    _myClassMock.Verify(ic => ic.DoStuffB(input), Times.Once());
}

If I call my method with It.IsAny<int>() as the input - VerifyMany(It.IsAny<int>()) - my tests don't pass, it will however work if I call the Verify method directly with It.IsAny: 如果我用It.IsAny<int>()作为输入调用我的方法 - VerifyMany(It.IsAny<int>()) - 我的测试没有通过,但是如果我直接使用它调用Verify方法,它将起作用.IsAny:

_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
_myClassMock.Verify(ic => ic.DoStuffB(It.IsAny<int>()), Times.Once());

I understand from the answer to this question that Moq handles It.IsAny differently within an expression when specified to Setup/Verify, is there any workaround for this? 我从这个问题的答案中理解,Moq处理It.IsAny在表达式中指定为Setup / Verify时,是否有任何解决方法?

The reason this doesn't work: 这不起作用的原因:

void VerifyMany(int input)
{
    _myClassMock.Verify(ic => ic.DoStuffA(input), Times.Once());
    _myClassMock.Verify(ic => ic.DoStuffB(input), Times.Once());
}

Is because It.IsAny<int>() (when simply invoked) returns 0. So essentially when VerifyMany is called with It.IsAny<int>() , you're passing 0 to VerifyMany . 是因为It.IsAny<int>()简单地调用时)返回0。所以基本上时VerifyMany被调用It.IsAny<int>()你传递0到VerifyMany Which in turn means DoStuffA(0) and DoStuffB(0) are verified (not Any integer value as you probably intended it). 这反过来意味着DoStuffA(0)DoStuffB(0)被验证(不是你可能想要的任何整数值)。

The other invocation: 另一个调用:

_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
_myClassMock.Verify(ic => ic.DoStuffB(It.IsAny<int>()), Times.Once());

Does work because the ic => ic.DoStuffA(It.IsAny<int>() part is never directly invoked. It is turned into an Expression Tree and Moq only walks (or visits if you like) that Expression Tree. Which means it will find It.IsAny<int>() in the Expression Tree and is then able to verify a call to DoStuffA (which it also found in the same expression tree) with any integer value. (for more on expression trees, feel free to read this ) 是否有效,因为ic => ic.DoStuffA(It.IsAny<int>()部分永远不会被直接调用。它变成了一个表达式树,Moq只能走路(或者如果你愿意,也可以访问)表达式树。这意味着它将在表达式树中找到It.IsAny<int>() ,然后能够验证对任何整数值的DoStuffA (它也在同一个表达式树中找到)的调用。(有关表达式树的更多信息,请随意读这个

You could make this semi-work by creating a method which abstracts the call to Verify away and accepts an expression like so: 您可以通过创建一个方法来完成这个半工作,该方法将对Verify的调用抽象出来并接受如下表达式:

void VerifyOnce(Expression<Action<ClassMockIsBasedOn>> callToVerify)
{
    _myClassMock.Verify(callToVerify, Times.Once());
}

Which allows you to call that like so: 这允许你像这样调用它:

VerifyOnce(ic => ic.DoStuffA(It.IsAny<int>())

You could also extend the VerifyOnce example to accept multiple expressions. 您还可以扩展VerifyOnce示例以接受多个表达式。 That would allow you to verify DoStuffA and DoStuffB on a single line: 这将允许您在DoStuffB上验证DoStuffADoStuffB

void VerifyOnce(params Expression<Action<ClassMockIsBasedOn>>[] callsToVerify)
{
    foreach(var callToVerify in callsToVerify) 
    {
        _myClassMock.Verify(callToVerify, Times.Once());
    }
}

That would allow a call like so: 那将允许这样的呼叫:

VerifyOnce(ic => ic.DoStuffA(It.IsAny<int>(),
           ic => ic.DoStuffB(It.IsAny<int>());

And of course you could replace ClassMockIsBasedOn with a generic. 当然,您可以使用泛型替换ClassMockIsBasedOn And add an overload which allows for methods which return values (instead of being void) or accept more than one parameter as Brett suggested in the comments. 并添加一个重载,它允许返回值(而不是为空)的方法或接受多个参数,如Brett在评论中建议的那样。

It.IsAny only allows Moq to match future invocations of method calls if used within the Setup construct, you can't do it with Verify or Assert if your Setup isn't set It.IsAny yet. It.IsAny只允许Moq匹配方法调用的未来调用(如果在Setup构造中使用),如果您的Setup未设置It.IsAny则无法使用VerifyAssert执行此操作。 Because It.IsAny always return a default value of input. 因为It.IsAny总是返回输入的默认值。

So if you want to use It.IsAny at Verify you should Setup for target method first: 因此,如果您想在Verify使用It.IsAny ,您应首先Setup目标方法:

Correct 正确

_myClassMock.Setup(ic => ic.DoStuffA(It.IsAny<int>())).Returns(// Something here);
_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());

Wrong 错误

_myClassMock.Setup(ic => ic.DoStuffA(1)).Returns(// Something here);
_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM