模拟方法执行时间和顺序
Mocking Method Execution Times and Sequence
我将 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"));
}
不应该通过,但是...
- 我需要做些什么来验证是否满足正确的顺序?
- 如何将两者结合起来,以便我可以测试执行次数和正确的顺序?
这可能比你想说的更离题,但 NSubstitute 是一个很好的模拟库,可以很好地处理这个问题。
在 NSubstitute 中,它只是:
var mock = Substitute.For<IInterface>();
var obj = new MyClass();
await obj.Run();
Received.InOrder(() => {
mock.MethodOne("foo");
mock.MethodTwo("foo");
});
您对 InSequence
的示例测试似乎顺序错误。在调用 Run
方法之前,您应该执行 Setup
。我假设这是一个拼写错误,您的实际测试会执行 Setup
,然后以正确的顺序调用该对象。也不清楚您对 IInterface
的模拟是如何达到 MyClass
的。在我的最后一个例子中,我假设它实际上被注入了...
Moq 的 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();
我将 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"));
}
不应该通过,但是...
- 我需要做些什么来验证是否满足正确的顺序?
- 如何将两者结合起来,以便我可以测试执行次数和正确的顺序?
这可能比你想说的更离题,但 NSubstitute 是一个很好的模拟库,可以很好地处理这个问题。 在 NSubstitute 中,它只是:
var mock = Substitute.For<IInterface>();
var obj = new MyClass();
await obj.Run();
Received.InOrder(() => {
mock.MethodOne("foo");
mock.MethodTwo("foo");
});
您对 InSequence
的示例测试似乎顺序错误。在调用 Run
方法之前,您应该执行 Setup
。我假设这是一个拼写错误,您的实际测试会执行 Setup
,然后以正确的顺序调用该对象。也不清楚您对 IInterface
的模拟是如何达到 MyClass
的。在我的最后一个例子中,我假设它实际上被注入了...
Moq 的 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();