模拟方法执行时间和顺序

ksp*_*rin 6 .net c# moq

我正在使用Moq与方法接口配对.我需要测试这个接口中的方法是按照一定的顺序执行的,也是每个方法执行一定次数的.

接口

public interface IInterface
{
    void MethodOne(string foo);
    void MethodTwo(string foo);
}
Run Code Online (Sandbox Code Playgroud)

方法

// MyClass stuff ...

public async Task Run()
{
    MethodOne("foo");
    MethodTwo("foo");
}

// ...
Run Code Online (Sandbox Code Playgroud)

测试

我写了这个测试来验证方法只执行了一定次数(一次):

[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());
}
Run Code Online (Sandbox Code Playgroud)

这很好......

我已经尝试过这些测试来确定某个序列是否得到了适当的满足,但测试似乎总是通过.

[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"));
}
Run Code Online (Sandbox Code Playgroud)

应该通过,并做...

[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"));
}
Run Code Online (Sandbox Code Playgroud)

不应该通过,但确实......

  1. 我需要做些什么来验证是否符合正确的顺序?
  2. 如何组合这两个,以便我可以测试执行次数和正确的顺序?

for*_*rir 9

您的示例测试InSequence似乎是错误的顺序.Setup在调用Run方法之前,您应该执行该操作.我假设这是一个错字,你的实际测试Setup,然后以正确的顺序调用对象.还不清楚你的模拟是如何IInterface得到的MyClass.在我的最后一个例子中,我假设它实际上是注入的......

InSequence如果你使用严格的模拟,Moq的支持似乎才有效.如果您创建Mock这样的:

var mock = new Mock<IInterface>(MockBehavior.Strict);
Run Code Online (Sandbox Code Playgroud)

然后这将工作:

mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo"));
Run Code Online (Sandbox Code Playgroud)

虽然失败了:

mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); // swapped order here
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
Run Code Online (Sandbox Code Playgroud)

注意,出现的错误是关于缺少相应设置的方法...而不是被称为不按顺序调用,如果你不期望它,这不一定是最容易解码的.

如果您不想/不能使用严格的模拟,那么替代方法是使用回调实现您自己的序列检查.像这样的东西:

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();
Run Code Online (Sandbox Code Playgroud)


Dan*_*ter 4

这可能比你想要的更偏离主题,但NSubstitute是一个很棒的模拟库,可以很好地处理这个问题。在 NSubstitute 中它只是:

  var mock = Substitute.For<IInterface>();
  var obj = new MyClass();
  await obj.Run();

  Received.InOrder(() => {
    mock.MethodOne("foo");
    mock.MethodTwo("foo");
    });
Run Code Online (Sandbox Code Playgroud)