![](/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.