想象一下这堂课
public class Foo {
private Handler _h;
public Foo(Handler h)
{
_h = h;
}
public void Bar(int i)
{
_h.AsyncHandle(CalcOn(i));
}
private SomeResponse CalcOn(int i)
{
...;
}
}
Run Code Online (Sandbox Code Playgroud)
Mo(q)cking Handler在Foo的测试中,我怎样才能检查Bar()传递给了_h.AsyncHandle什么?
Gam*_*lor 251
您可以使用Mock.Callback方法:
var mock = new Mock<Handler>();
SomeResponse result = null;
mock.Setup(h => h.AnsyncHandle(It.IsAny<SomeResponse>()))
.Callback<SomeResponse>(r => result = r);
// do your test
new Foo(mock.Object).Bar(22);
Assert.NotNull(result);
Run Code Online (Sandbox Code Playgroud)
如果您只想在传入的参数中检查一些简单的东西,您也可以直接执行:
mock.Setup(h => h.AnsyncHandle(It.Is<SomeResponse>(response => response != null)));
Run Code Online (Sandbox Code Playgroud)
Joh*_*nny 48
另一种方法是使用Capture.In,这是 Moq 中的开箱即用功能,可让您将参数捕获到集合中:
//Arrange
var args = new List<SomeResponse>();
mock.Setup(h => h.AsyncHandle(Capture.In(args)));
//Act
new Foo(mock.Object).Bar(22);
//Assert
//... assert args.Single() or args.First()
Run Code Online (Sandbox Code Playgroud)
Pet*_*tin 21
Gamlor的回答是有效的,但另一种做法(以及我认为在测试中更具表现力的一种方式)是......
var mock = new Mock<Handler>();
var desiredParam = 47; // this is what you want to be passed to AsyncHandle
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(desiredParam), Times.Once());
Run Code Online (Sandbox Code Playgroud)
验证非常强大,值得花时间习惯.
Jav*_*udt 18
Gamlor的回答对我有用,但我想我会扩展John Carpenter的评论,因为我正在寻找一个涉及多个参数的解决方案.我认为偶然发现此页面的其他人可能处于类似情况.我在Moq文档中找到了这个信息.
我将使用Gamlor的示例,但让我们假装AsyncHandle方法有两个参数:a string和一个SomeResponse对象.
var mock = new Mock<Handler>();
string stringResult = string.Empty;
SomeResponse someResponse = null;
mock.Setup(h => h.AsyncHandle(It.IsAny<string>(), It.IsAny<SomeResponse>()))
.Callback<string, SomeResponse>((s, r) =>
{
stringResult = s;
someResponse = r;
});
// do your test
new Foo(mock.Object).Bar(22);
Assert.AreEqual("expected string", stringResult);
Assert.IsNotNull(someResponse);
Run Code Online (Sandbox Code Playgroud)
基本上,您只需要It.IsAny<>()使用适当的类型添加另一个类型,向该Callback方法添加另一个类型,并根据需要更改lambda表达式.
And*_*ord 18
Callback方法肯定会起作用,但如果你在一个有很多参数的方法上这样做,它可能有点冗长.这是我用来删除一些样板的东西.
var mock = new Mock<Handler>();
// do your test
new Foo(mock.Object).Bar(22);
var arg = new ArgumentCaptor<SomeResponse>();
mock.Verify(h => h.AsyncHandle(arg.Capture()));
Assert.NotNull(arg.Value);
Run Code Online (Sandbox Code Playgroud)
以下是ArgumentCaptor的来源:
public class ArgumentCaptor<T>
{
public T Capture()
{
return It.Is<T>(t => SaveValue(t));
}
private bool SaveValue(T t)
{
Value = t;
return true;
}
public T Value { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
小智 7
这也有效:
Mock<InterfaceThing> mockedObject = new Mock<InterfaceThing>();
var objectParameter = mockedObject.Invocations[1].Arguments[0] as ObjectParameter;
Run Code Online (Sandbox Code Playgroud)
您可以使用It.Is<TValue>()匹配器。
var mock = new Mock<Handler>();
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(It.Is<SomeResponse>(r => r != null )));
Run Code Online (Sandbox Code Playgroud)