如何验证的xUnit起订量执行顺序?(How to verify order of executio

2019-10-20 05:09发布

我有以下类:

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

    public Stream TestStream;

    public WriteToTestStream()
    { ... }
}

WriteToTestStream写入TestStream

我想写一个单元测试来确保

  1. Prop1Prop2被写入到之前设置TestStream
  2. 一旦事情被写入的属性不应该访问TestStream

我如何定义一个模拟WriteToTestStream在这种情况下? 如何操作从嘲笑函数的局部变量(我可以使用局部变量在单元测试时要记住的流写入/属性设定)?

Answer 1:

要做到这一点的方法之一是保持本地状态变量,然后用起订量的回调跟踪状态下,可以Assert的回调内,以确保正确的状态。 下面是一个例子(尽管在NUnit的)。 我还以为你真的想测试它采用了SUT Foo以正确的顺序(我称为SUT Bar在这里)。

[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类,方法和属性必须克服的,例如,所有的虚拟或抽象接口。

下面是这种重构的例子:

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;
    }
}

这样做的另一种方法可以是使用迪克兰惠兰的 MoqSequences扩展 ,尽管我必须承认我还没有使用它。

编辑

看来, MockSequenceInSequence ),已使它成为最新版本的Moq ,虽然这可能会强制执行非常严格的顺序,也似乎需要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());
    }
}


文章来源: How to verify order of execution in XUnit Moq?