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

C# 如何验证XUnit Moq中的执行顺序?,c#,unit-testing,moq,xunit,xunit.net,C#,Unit Testing,Moq,Xunit,Xunit.net,我有以下课程: public class Foo { public int Prop1 { get; set; } public string Prop2 { get; set; } public Stream TestStream; public WriteToTestStream() { ... } } WriteToTestStream写入TestStream 我想写一个单元测试来确保 Prop1和Prop2在写入TestStream 一旦将某

我有以下课程:

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

    public Stream TestStream;

    public WriteToTestStream()
    { ... }
}
WriteToTestStream
写入
TestStream

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

  • Prop1
    Prop2
    在写入
    TestStream
  • 一旦将某些内容写入
    TestStream
    ,就不应该访问这些属性
  • 在这种情况下,如何为
    WriteToTestStream
    定义模拟?
    如何从模拟函数中操作局部变量(我可以在单元测试中使用局部变量来记住何时写入流/设置属性)?

    一种方法是保留局部状态变量,然后使用Moq回调来跟踪状态,您可以在回调中断言,以确保状态正确。这里有一个例子(尽管是在努尼特)。我还假设您实际上想要测试以正确顺序使用
    Foo
    的SUT(我在这里调用了SUT
    Bar

    另一种方法是使用,尽管我必须承认我还没有用过

    编辑

    似乎
    MockSequence
    insesequence
    )具有,尽管这可能会强制执行非常严格的序列,并且似乎还需要:

    [TestFixture]
    公共类单元测试
    {
    私人模拟(mockFoo),;
    [设置]
    公共作废设置()
    {
    _mockFoo=newmock(MockBehavior.Strict);
    var seq=新的模拟序列();
    _mockFoo.InSequence(seq).SetupSet(m=>m.Prop1=It.IsAny());
    _mockFoo.InSequence(seq).SetupSet(m=>m.Prop2=It.IsAny());
    _mockFoo.InSequence(seq).Setup(m=>m.WriteToTestStream());
    }
    [测试]
    公共秩序
    {
    var sut=新条(_mockFoo.Object);
    Assert.doesnothrow(()=>sut.doSomethingOrder());
    }
    [测试]
    公共无效保证自动福特()
    {
    var sut=新条(_mockFoo.Object);
    Assert.Catch(()=>sut.DoSomethingOutOfOrder());
    }
    }
    
    谢谢你,斯图尔特。回调的解决方案适合我。不过,我认为有一个不连贯的问题。我读到它对同一个模拟对象不起作用老实说,我没有发现很多情况下需要验证调用依赖项方法的顺序(在我看来,这通常是白盒/实现细节)。但是,为了提供返回数据序列,我通常使用
    ReturnsInOrder
    扩展名
    [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());
        }
    }
    
    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;
        }
    }
    
    [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());
        }
    }