Pergunta

Recentemente comecei a usar AutoFixture+AutoMoq e estou tentando criar uma instância de Func<IDbConnection> (ou seja, uma connection factory).

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

Isso parece funcionar muito bem:

  1. Meu sistema em teste pode chamar o delegado e obterá uma simulação de IDbConnection
  2. Para o qual posso ligar CreateCommand, o que me dará uma zombaria IDbCommand
  3. Para o qual posso ligar ExecuteReader, o que me dará uma zombaria IDataReader

Agora quero realizar configurações adicionais no mock de IDataReader, como fazê-lo retornar true quando Read() é chamado.

Pelo que li, deveria estar usando Freeze por esta:

var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();

dataReaderMock.Setup(dr => dr.Read())
                      .Returns(true);

Isso não parece atender às minhas expectativas.Quando eu ligo IDbCommand.ExecuteReader, obterei um leitor diferente daquele que acabei de congelar/configurar.

Aqui está um exemplo:

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

O que estou fazendo de errado?Como consigo outros fixtures, como IDbCommand, para usar a instância simulada de IDataReader?

Foi útil?

Solução

A partir da versão 3.20.0, você pode usar AutoConfiguredMoqCustomization.Isso configurará automaticamente todos os mocks para que os valores de retorno de seus membros sejam gerados pelo AutoFixture.

Por exemplo., IDbConnetion.CreateCommand será configurado automaticamente para retornar um IDbCommand do aparelho, e IDbCommand.ExecuteReader será configurado automaticamente para retornar um IDataReader do aparelho.

Todos esses testes devem passar agora:

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

Outras dicas

Você tem que Freeze o Mock<IDbCommand> também – e configure o objeto simulado (como um Stub) para retornar o existente dataReaderMock.Object instância.

Se você adicionar o seguinte à fase de organização do seu teste, o teste será aprovado:

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

Embora a solução do Nikos funcione, eu não recomendaria zombar do ado.net.

Na minha opinião, seus testes provavelmente serão difíceis de entender, manter e não lhe darão a confiança que deveriam lhe dar.

Eu consideraria testar sua camada de dados indo até o banco de dados, mesmo que seja mais lento.

Eu recomendaria a leitura deste artigo sobre as melhores práticas para zombaria:http://codebetter.com/jeremymiller/2006/01/10/best-and-worst-practices-for-mock-objects/

Não zombe dos outros:http://aspiringcraftsman.com/2012/04/01/tdd-best-practices-dont-mock-others/

Não sei sua situação exata, mas de qualquer forma gostaria de compartilhar isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top