我正在使用Moq与方法接口配对。我需要测试一下这个接口中的方法是按照一定的顺序执行的,每次都要执行一定次数。
public interface IInterface
{
void MethodOne(string foo);
void MethodTwo(string foo);
}
// MyClass stuff ...
public async Task Run()
{
MethodOne("foo");
MethodTwo("foo");
}
// ...
我已经编写了这个测试来验证这些方法只执行了一定次数(一次):
[TestMethod]
public async Task Test()
{
var mock = new Mock<IInterface>();
var mockSequence = new MockSequence();
var obj = new MyClass();
await obj.Run();
mock.Verify(i=> i.MethodOne("foo"), Times.Once());
mock.Verify(i=> i.MethodTwo("foo"), Times.Once());
}
这很好......
我已经尝试过这些测试来确定某个序列是否得到了适当的满足,但测试似乎总是通过。
[TestMethod]
public async Task Test()
{
var mock = new Mock<IInterface>();
var mockSequence = new MockSequence();
var obj = new MyClass();
await obj.Run();
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo"));
}
应该通过,并且确实......
[TestMethod]
public async Task Test()
{
var mock = new Mock<IInterface>();
var mockSequence = new MockSequence();
var obj = new MyClass();
await obj.Run();
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); // swapped order here
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
}
不应该通过,但确实......
答案 0 :(得分:8)
InSequence
的示例测试似乎顺序错误。在调用Setup
方法之前,您应该执行Run
。我认为这是一个错字,你的实际测试是Setup
,然后以正确的顺序调用对象。它还不清楚你对IInterface
的模拟如何到达MyClass
。在我的最后一个例子中,我已经假设它实际注入了......
InSequence
支持似乎才有效。如果你像这样创建Mock
:
var mock = new Mock<IInterface>(MockBehavior.Strict);
然后这将起作用:
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo"));
虽然失败了:
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); // swapped order here
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
注意,出现的错误是关于缺少相应设置的方法...而不是按顺序调用它,如果你不期望它,这不一定是最容易解码的。
如果您不想/不能使用严格的模拟,替代方法是使用回调实现您自己的序列检查。像这样:
int sequence = 1;
mock.Setup(i => i.MethodOne("foo"))
.Callback(()=>Assert.AreEqual(1, sequence++, "Method called out of sequence"));
mock.Setup(i => i.MethodTwo("foo"))
.Callback(() => Assert.AreEqual(2, sequence++, "Method called out of sequence"));
var obj = new MyClass(mock.Object);
await obj.Run();
答案 1 :(得分:4)
这可能比你想要的更偏离主题,但NSubstitute是一个很好的模拟库,可以很好地处理这个问题。 在NSubstitute它只是:
var mock = Substitute.For<IInterface>();
var obj = new MyClass();
await obj.Run();
Received.InOrder(() => {
mock.MethodOne("foo");
mock.MethodTwo("foo");
});