我最近开始使用AutoFixture + AutoMoq,我正在尝试创建Func<IDbConnection>
的实例(即连接工厂)。
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var connectionFactory = fixture.Create<Func<IDbConnection>>();
这似乎工作得很好:
IDbConnection
CreateCommand
,这会让我模仿IDbCommand
ExecuteReader
,这会让我模仿IDataReader
我现在想要在模拟IDataReader
时执行其他设置,例如在调用true
时让它返回Read()
。
根据我的阅读,我应该使用Freeze
:
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
这似乎不符合我的期望。当我拨打IDbCommand.ExecuteReader
时,我会得到一个与我刚冻结/设置的读者不同的读者。
以下是一个例子:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
//true - Create<IDataReader> retrieves the data reader I just mocked
Assert.AreSame(dataReaderMock.Object, fixture.Create<IDataReader>());
//false - IDbCommand returns a different instance of IDataReader
Assert.AreSame(dataReaderMock.Object, fixture.Create<IDbCommand>().ExecuteReader());
我做错了什么?如何使用其他灯具(例如IDbCommand
)来使用IDataReader
的模拟实例?
答案 0 :(得分:5)
从3.20.0开始,您可以使用AutoConfiguredMoqCustomization
。这将自动配置所有模拟,以便其成员的返回值由AutoFixture生成。
例如,IDbConnetion.CreateCommand
将自动配置为从灯具返回IDbCommand
,IDbCommand.ExecuteReader
将自动配置为从灯具返回IDataReader
。
现在所有这些测试都应该通过:
var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
//all pass
Assert.Same(dataReaderMock.Object, fixture.Create<IDataReader>());
Assert.Same(dataReaderMock.Object, fixture.Create<IDbCommand>().ExecuteReader());
Assert.Same(dataReaderMock.Object, fixture.Create<IDbConnection>().CreateCommand().ExecuteReader());
Assert.Same(dataReaderMock.Object, fixture.Create<Func<IDbConnection>>()().CreateCommand().ExecuteReader());
答案 1 :(得分:3)
您还必须Freeze
Mock<IDbCommand>
- 并设置模拟对象(作为存根)以返回现有的dataReaderMock.Object
实例。
如果您将以下内容添加到测试的编配阶段,测试将通过:
var dbCommandStub =
fixture
.Freeze<Mock<IDbCommand>>()
.Setup(x => x.ExecuteReader())
.Returns(dataReaderMock.Object);
答案 2 :(得分:1)
虽然Nikos的解决方案有效,但我不建议嘲笑ado.net。
在我看来,您的测试可能很难理解,维护并且不会让您对测试给您的信心。
我会考虑通过一直到数据库来测试你的数据层,即使它比较慢。
我建议阅读本文关于模拟的最佳做法: http://codebetter.com/jeremymiller/2006/01/10/best-and-worst-practices-for-mock-objects/
不要嘲笑他人: http://aspiringcraftsman.com/2012/04/01/tdd-best-practices-dont-mock-others/
我不知道你的确切情况,但无论如何我想分享这个。