Издевательство над зависимостью с помощью автофиксации

StackOverflow https://stackoverflow.com//questions/25055661

Вопрос

Недавно я начал использовать 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.Это автоматически настроит все макеты таким образом, чтобы возвращаемые значения их элементов генерировались с помощью автофиксации.

Напр., 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());

Другие советы

Ты должен Freeze то Mock<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