5

我最近开始使用 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使其返回。trueRead()

从我读过的内容来看,我应该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

4

3 回答 3

7

从 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());
于 2014-08-21T17:43:55.407 回答
4

您也必须Freeze这样Mock<IDbCommand>做 - 并设置模拟对象(作为存根)以返回现有dataReaderMock.Object实例。

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

var dbCommandStub = 
    fixture
        .Freeze<Mock<IDbCommand>>()
        .Setup(x => x.ExecuteReader())
        .Returns(dataReaderMock.Object);
于 2014-07-31T10:54:41.803 回答
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/

我不知道你的确切情况,但无论如何我想分享这个。

于 2014-08-03T17:18:12.680 回答