繁体   English   中英

如何验证XUnit Moq中的执行顺序?

[英]How to verify order of execution in XUnit Moq?

我有以下课程:

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的模拟? 如何从Mocked函数操作局部变量(可以在单元测试中使用局部变量来记住何时编写Stream /设置属性)?

要做到这一点的方法之一是保持本地状态变量,然后用起订量的回调跟踪状态下,可以Assert的回调内,以确保正确的状态。 这是一个示例(尽管在NUnit中)。 我还假设您实际上是要测试以正确顺序使用Foo的SUT(在这里我将其称为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;
    }
}

做到这一点的另一种方法可能是使用Declan Whelan的 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());
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM