如何验证XUnit Moq中的执行顺序? [英] How to verify order of execution in XUnit Moq?

查看:155
本文介绍了如何验证XUnit Moq中的执行顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下课程:

public class Foo
{
    public int Prop1 { get; set; }
    public string Prop2 { get; set; }

    public Stream TestStream;

    public WriteToTestStream()
    { ... }
}

WriteToTestStream写入TestStream.

我想编写一个单元测试以确保

I want to write a Unit Test to make sure that

    在写入TestStream 之前已设置
  1. Prop1Prop2
  2. 一旦将内容写入TestStream,就不应访问属性.
  1. Prop1 and Prop2 are being set before writing to the TestStream
  2. The properties should not be accessed once something is written to the TestStream.

在这种情况下,如何为WriteToTestStream定义模拟? 如何从Mocked函数操作局部变量(我可以在单元测试中使用局部变量来记住何时编写Stream/设置属性)?

How can I define a Mock for WriteToTestStream in this case? How can I manipulate local variables from a Mocked function(I can use local variables in the Unit Test to remember when the Stream was written / properties were set)?

推荐答案

一种方法是保留局部状态变量,然后使用Moq的回调来跟踪状态,您可以在回调中Assert以确保正确状态.这是一个示例(尽管在NUnit中).我还假设您实际上要测试按正确顺序使用Foo的SUT(我在这里将其称为Bar).

One way to do this is by keeping local state variables and then using Moq's callbacks to track the state, you can Assert within the callbacks to ensure the correct state. Here's an example (Albeit in NUnit). I've also assumed that you actually want to test a SUT which uses Foo in the correct order (I've called the SUT Bar here).

[TestFixture]
public class UnitTest
{
    private bool _prop1Set = false;
    private bool _prop2Set = false;
    private Mock<IFoo> _mockFoo;

    [SetUp]
    public void Setup()
    {
        _mockFoo = new Mock<IFoo>();
        _mockFoo.SetupSet(m => m.Prop1).Callback(i => _prop1Set = true);
        _mockFoo.SetupSet(m => m.Prop2).Callback(s => _prop2Set = true);
        _mockFoo.Setup(m => m.WriteToTestStream())
                .Callback(() => Assert.IsTrue(_prop1Set && _prop2Set));
    }

    [Test]
    public void EnsureInOrder()
    {
        var sut = new Bar(_mockFoo.Object);
        Assert.DoesNotThrow(() => sut.DoSomethingInOrder());
    }

    [Test]
    public void EnsureOutOfOrder()
    {
        var sut = new Bar(_mockFoo.Object);
        Assert.Catch<Exception>(() => sut.DoSomethingOutOfOrder());
    }
}

请注意,要模拟您的Foo类,方法和属性必须是可重写的,例如全部是虚拟的或具有抽象的接口.

Note that in order to Mock your Foo class, methods and properties need to be overridable, e.g. all virtual or with an abstracted interface.

这是这种重构的一个例子:

Here's an example of such refactoring:

public interface IFoo
{
    int Prop1 { get; set; }
    string Prop2 { get; set; }
    void WriteToTestStream();
}

public class Foo : IFoo
{
    public int Prop1 { get; set; }
    public string Prop2 { get; set; }
    // Surely this is internal implementation
    private Stream TestStream;
    public void WriteToTestStream() { }
}

public class Bar
{
    private readonly IFoo _foo;
    public Bar(IFoo injectedFoo)
    {
        _foo = injectedFoo;
    }

    public void DoSomethingInOrder()
    {
        _foo.Prop1 = 1;
        _foo.Prop2 = "Baz";
        _foo.WriteToTestStream();
    }

    public void DoSomethingOutOfOrder()
    {
        _foo.WriteToTestStream();
        _foo.Prop2 = "Baz";
        _foo.Prop1 = 1;
    }
}

另一种方法可以使用 Declan Whelan's

Another way of doing this could be to use Declan Whelan's MoqSequences extension, although I must admit I haven't used it yet.

修改

MockSequence(InSequence)似乎已将设置为最新版本的Moq ,尽管这可能会强制执行非常严格的序列,并且似乎还需要 MockBehavior.Strict a>:

It appears that MockSequence (InSequence) has made it into recent versions of Moq, although this might enforce a very rigid sequence, and also appears to require MockBehavior.Strict:

[TestFixture]
public class UnitTest
{
    private Mock<IFoo> _mockFoo;

    [SetUp]
    public void Setup()
    {
        _mockFoo = new Mock<IFoo>(MockBehavior.Strict);
        var seq = new MockSequence();
        _mockFoo.InSequence(seq).SetupSet(m => m.Prop1 = It.IsAny<int>());
        _mockFoo.InSequence(seq).SetupSet(m => m.Prop2 = It.IsAny<string>());
        _mockFoo.InSequence(seq).Setup(m => m.WriteToTestStream());
    }

    [Test]
    public void EnsureInOrder()
    {
        var sut = new Bar(_mockFoo.Object);
        Assert.DoesNotThrow(() => sut.DoSomethingInOrder());
    }

    [Test]
    public void EnsureOutOfOrder()
    {
        var sut = new Bar(_mockFoo.Object);
        Assert.Catch<MockException>(() => sut.DoSomethingOutOfOrder());
    }
}

这篇关于如何验证XUnit Moq中的执行顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆