我有两个这样的界面:
public interface Store { Tx BeginTx() }
public interface Tx { void Write() }
我有一个像这样的方法:
void WriteALot(fakeStore)
{
var tx1 = fakeStore.BeginTx();
tx1.Write();
var tx2 = fakeStore.BeginTx();
tx2.Write();
}
和测试:
var fakeStore = A.Fake<Store>(x => x.Wrapping(realstore));
// A.CallTo(() => fakeStore.BeginTx()).ReturnAWrappedTx()?
WriteALot(fakeStore);
// Check that a total of two calls were made to the Tx's
可以做到吗?
编辑:
我应该澄清,实际上将有数百个事务,并且每个事务都有多个Write-call。并且Store和Tx的实现非常复杂。这是一个集成测试,我使用FakeItEasy来检查不同设置下的批处理行为。不过,这可能与该库的预期用例相差太远了:)
我想我要问的是,我是否可以不手动进行收集并最好合并伪造的交易。我可以想象像ReturnLazily这样的东西,它具有收集返回的假货的副作用,但是这非常难以管理且难以阅读(而且我无法使断言部分起作用)。
答案 0 :(得分:1)
假设您打算在上面编写tx1.Write
和tx2.Write
,则可以轻松地检查每个事务是否被调用一次,这可能比检查总共进行两次调用更有用:>
public void Test()
{
var realStore = new RealStore();
var fakeStore = A.Fake<Store>(x => x.Wrapping(realStore));
var realTransaction1 = new RealTransaction();
var realTransaction2 = new RealTransaction();
var wrappedTransaction1 = A.Fake<Tx>(options => options.Wrapping(realTransaction1));
var wrappedTransaction2 = A.Fake<Tx>(options => options.Wrapping(realTransaction2));
A.CallTo(() => fakeStore.BeginTx())
.Returns(wrappedTransaction1).Once().Then
.Returns(wrappedTransaction2);
WriteALot(fakeStore);
A.CallTo(() => wrappedTransaction1.Write()).MustHaveHappenedOnceExactly();
A.CallTo(() => wrappedTransaction2.Write()).MustHaveHappenedOnceExactly();
}
但是,如果您确实要确保在不检查每个事务是否负责1次写入的情况下进行了两次调用,则可以
[Test]
public void LaxTest()
{
int numberOfTransactionCalls = 0;
var realStore = new RealStore();
var fakeStore = A.Fake<Store>(x => x.Wrapping(realStore));
var realTransaction1 = new RealTransaction();
var realTransaction2 = new RealTransaction();
var wrappedTransaction1 = A.Fake<Tx>(options => options.Wrapping(realTransaction1));
var wrappedTransaction2 = A.Fake<Tx>(options => options.Wrapping(realTransaction2));
A.CallTo(() => wrappedTransaction1.Write()).Invokes(() => ++numberOfTransactionCalls);
A.CallTo(() => wrappedTransaction2.Write()).Invokes(() => ++numberOfTransactionCalls);
A.CallTo(() => fakeStore.BeginTx())
.Returns(wrappedTransaction1).Once().Then
.Returns(wrappedTransaction2);
WriteALot(fakeStore);
Assert.That(numberOfTransactionCalls, Is.EqualTo(2));
}
请注意,如果您的生产方法确实像您发布的那样简单,则无需委托给实际的实现,则可以省略所有包装:
[Test]
public void UnwrappedTest()
{
var fakeStore = A.Fake<Store>();
var transaction1 = A.Fake<Tx>();
var transaction2 = A.Fake<Tx>();
A.CallTo(() => fakeStore.BeginTx())
.Returns(transaction1).Once().Then
.Returns(transaction2);
WriteALot(fakeStore);
A.CallTo(() => transaction1.Write()).MustHaveHappenedOnceExactly();
A.CallTo(() => transaction2.Write()).MustHaveHappenedOnceExactly();
}
在我看来,了解正在发生的事情要容易得多。但是也许您只是为了提出问题而简化了。
答案 1 :(得分:1)
在更新的要求下,我尝试了这种方法,并通过了。我敢肯定它仍然过于简单化,但是听起来您的测试会变得千变万化,而且我确实没有机会编写适合您特定用例的东西。但是,通过引入一个小的工厂类,我达到了某种程度的可读性(在我看来),并且能够收集所创建的事务:
private class TransactionFactory
{
private readonly IList<Tx> allTransactions = new List<Tx>();
public IEnumerable<Tx> AllTransactions => allTransactions;
public Tx Create()
{
var realTransaction = new RealTransaction();
var fakeTransaction = A.Fake<Tx>(options =>
options.Wrapping(realTransaction));
allTransactions.Add(fakeTransaction);
return fakeTransaction;
}
}
[Test]
public void UpdatedTests()
{
var realStore = new RealStore();
var fakeStore = A.Fake<Store>(x => x.Wrapping(realStore));
var transactionFactory = new TransactionFactory();
A.CallTo(() => fakeStore.BeginTx()).ReturnsLazily(transactionFactory.Create);
WriteALot(fakeStore);
Assert.That(transactionFactory.AllTransactions.SelectMany(Fake.GetCalls).Count(),
Is.EqualTo(2));
}
这应该可以进行各种修改,但是正如您所指出的,这并不是FakeItEasy的预期用途,因此您可能最终会在库周围进行大量自定义编码。