想象一下这个班级
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)
{
...;
}
}
Mo(q)cking Handler在Foo的测试中,我如何能够检查Bar()
传递给_h.AsyncHandle
的内容?
答案 0 :(得分:229)
您可以使用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);
如果你只想在传入的参数中检查一些简单的东西,你也可以直接进行:
mock.Setup(h => h.AnsyncHandle(It.Is<SomeResponse>(response => response != null)));
答案 1 :(得分:19)
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());
验证非常强大,值得花些时间习惯。
答案 2 :(得分:15)
Gamlor的回答对我有用,但我想我会扩展John Carpenter的评论,因为我正在寻找一个涉及多个参数的解决方案。我认为偶然发现此页面的其他人可能处于类似情况。我在Moq documentation。
中找到了此信息我将使用Gamlor的示例,但让我们假装AsyncHandle方法有两个参数: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);
基本上你只需要用适当的类型添加另一个It.IsAny<>()
,在Callback
方法中添加另一个类型,并根据需要更改lambda表达式。
答案 3 :(得分:11)
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);
以下是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; }
}
答案 4 :(得分:4)
您可以使用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 )));
答案 5 :(得分:0)
这也有效:
Mock<InterfaceThing> mockedObject = new Mock<InterfaceThing>();
var objectParameter = mockedObject.Invocations[1].Arguments[0] as ObjectParameter;
答案 6 :(得分:0)
还可以使用Capture.In
的{{1}}功能。 OOTB moq
功能可以在集合中捕获参数。
moq
答案 7 :(得分:0)
这里有很多好的答案!使用开箱即用的Moq功能集,直到需要对传递给依赖项的几个类参数进行断言为止。如果最终遇到这种情况,它的Moq验证功能是匹配器不能很好地隔离测试失败,返回/回调方法捕获参数会在测试中添加不必要的代码行(并且对我来说,长时间测试是不行的。
这里是要点:https://gist.github.com/Jacob-McKay/8b8d41ebb9565f5fca23654fd944ac6b具有我写过的Moq(4.12)扩展名,它提供了一种更具声明性的方式来对传递给模拟的参数进行断言,而没有上述缺点。这是“验证”部分现在的样子:
mockDependency
.CheckMethodWasCalledOnce(nameof(IExampleDependency.PersistThings))
.WithArg<InThing2>(inThing2 =>
{
Assert.Equal("Input Data with Important additional data", inThing2.Prop1);
Assert.Equal("I need a trim", inThing2.Prop2);
})
.AndArg<InThing3>(inThing3 =>
{
Assert.Equal("Important Default Value", inThing3.Prop1);
Assert.Equal("I NEED TO BE UPPER CASED", inThing3.Prop2);
});
如果Moq提供的功能可以在声明时实现相同的功能,并提供故障隔离功能,那我会很高兴。手指交叉!