用AutoFixture模拟依赖项
本文关键字:依赖 模拟 AutoFixture | 更新日期: 2023-09-27 18:15:42
我最近开始使用AutoFixture+AutoMoq,我试图创建一个Func<IDbConnection>
的实例(即连接工厂)。
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var connectionFactory = fixture.Create<Func<IDbConnection>>();
这似乎工作得相当好:
- 我的被测系统可以调用委托,它将获得
IDbConnection
的模拟 - 然后我可以调用
CreateCommand
,这将获得IDbCommand
的模拟 - 然后我可以调用
ExecuteReader
,这将获得IDataReader
的模拟
我现在想在IDataReader
的模拟上执行额外的设置,例如在调用Read()
时使其返回true
。
从我所读到的,我应该使用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());
我做错了什么?如何让其他fixture(如IDbCommand
)使用IDataReader
的模拟实例?
从3.20.0开始,您可以使用AutoConfiguredMoqCustomization
。这将自动配置所有mock,使其成员的返回值由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());
您还必须对Mock<IDbCommand>
进行Freeze
,并设置模拟对象(作为存根)以返回现有的dataReaderMock.Object
实例。
如果在测试的Arrange阶段添加以下内容,测试将通过:
var dbCommandStub =
fixture
.Freeze<Mock<IDbCommand>>()
.Setup(x => x.ExecuteReader())
.Returns(dataReaderMock.Object);
虽然Nikos的解决方案可以工作,但我不建议mock 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/
我不知道你的确切情况,但无论如何我想分享这个