我最近开始使用 AutoFixture+AutoMoq 并且我正在尝试创建一个实例 Func<IDbConnection> (即连接工厂)。

var fixture = new Fixture().Customize(new AutoMoqCustomization());
var connectionFactory = fixture.Create<Func<IDbConnection>>();

这似乎工作得相当好:

  1. 我的被​​测系统可以调用委托,它将得到一个模拟 IDbConnection
  2. 然后我可以打电话 CreateCommand, ,这会让我嘲笑 IDbCommand
  3. 然后我可以打电话 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?

有帮助吗?

解决方案

从 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());

其他提示

你必须 FreezeMock<IDbCommand> 以及 - 并设置模拟对象(作为存根)以返回现有的 dataReaderMock.Object 实例。

如果将以下内容添加到测试的排列阶段,测试将通过:

var dbCommandStub = 
    fixture
        .Freeze<Mock<IDbCommand>>()
        .Setup(x => x.ExecuteReader())
        .Returns(dataReaderMock.Object);

虽然 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/

我不知道你的具体情况,但无论如何我想分享一下。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top