![](/img/trans.png)
[英]How to verify with XUnit that method was called or was not called without 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
。
我想编写一个单元测试以确保
Prop1
和Prop2
被写入到之前设置TestStream
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
扩展 ,尽管我必须承认我还没有使用过它。
编辑
看起来MockSequence
( InSequence
)已将其添加到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.