【问题标题】:How to verify order of execution in XUnit Moq?如何验证 XUnit Moq 中的执行顺序?
【发布时间】:2014-07-24 12:07:23
【问题描述】:

我有以下课程:

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

【问题讨论】:

    标签: c# unit-testing moq xunit xunit.net


    【解决方案1】:

    一种方法是保留本地状态变量,然后使用 Moq 的回调来跟踪状态,您可以在回调中 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'sMoqSequences extension,尽管我必须承认我还没有使用它。

    编辑

    似乎MockSequence (InSequence) 具有made it into recent versions of 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());
        }
    }
    

    【讨论】:

    • 谢谢斯图尔特。回调的解决方案对我有用。我认为 InSequence 存在问题。我读到它不适用于同一个 Mock 对象。 - code.google.com/p/moq/issues/detail?id=291
    • 很可能 - 老实说,我还没有发现很多我想验证调用依赖项方法的顺序的情况(IMO 这通常是白盒/实现细节)。但是,为了提供一系列返回数据,我通常使用ReturnsInOrder 扩展here
    猜你喜欢
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    • 2020-08-29
    • 1970-01-01
    • 2012-05-23
    相关资源
    最近更新 更多