使用 FakeItEasy 检查对多个返回的、包装的假货的调用
Checking calls on multiple returned, wrapped fakes with FakeItEasy
我有两个这样的界面:
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
这可以做到吗?
编辑:
我应该澄清一下,实际上会有数百个事务和对每个事务的多个写入调用。 Store和Tx的实现很复杂。这是用于集成测试,我使用 FakeItEasy 检查不同设置下的批处理行为。虽然它可能与库的预期用例有点太远了:)
我想我想问的是我是否可以收集并最好合并伪造的交易,而无需手动进行。我可以想象像 ReturnLazily 这样的东西具有收集返回的假货的副作用,但这非常难以管理且难以阅读(而且我无法让断言部分工作)。
假设你打算在上面写 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));
}
请注意,如果您的生产方法真的像您一样简单 post,则无需委托给实际实现,您可以省略所有包装:
[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();
}
在我看来,理解正在发生的事情要容易得多。但也许你只是为了问问题而简化了。
随着需求的更新,我尝试了这种东西,通过了。我敢肯定它仍然过于简单化,但听起来您的测试会多种多样且怪异,而且我真的没有机会编写适合您特定用例的东西。然而,通过引入一个小工厂 class,我实现了一定程度的可读性(在我看来),并且能够收集创建的交易:
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 预期的使用方式,因此您最终可能会围绕库进行大量自定义编码。
我有两个这样的界面:
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
这可以做到吗?
编辑:
我应该澄清一下,实际上会有数百个事务和对每个事务的多个写入调用。 Store和Tx的实现很复杂。这是用于集成测试,我使用 FakeItEasy 检查不同设置下的批处理行为。虽然它可能与库的预期用例有点太远了:)
我想我想问的是我是否可以收集并最好合并伪造的交易,而无需手动进行。我可以想象像 ReturnLazily 这样的东西具有收集返回的假货的副作用,但这非常难以管理且难以阅读(而且我无法让断言部分工作)。
假设你打算在上面写 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));
}
请注意,如果您的生产方法真的像您一样简单 post,则无需委托给实际实现,您可以省略所有包装:
[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();
}
在我看来,理解正在发生的事情要容易得多。但也许你只是为了问问题而简化了。
随着需求的更新,我尝试了这种东西,通过了。我敢肯定它仍然过于简单化,但听起来您的测试会多种多样且怪异,而且我真的没有机会编写适合您特定用例的东西。然而,通过引入一个小工厂 class,我实现了一定程度的可读性(在我看来),并且能够收集创建的交易:
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 预期的使用方式,因此您最终可能会围绕库进行大量自定义编码。