Usando IoC para testes de unidade

97

Como um contêiner IoC pode ser usado para testes de unidade? É útil gerenciar mocks em uma solução enorme (mais de 50 projetos) usando IoC? Alguma experiência? Alguma biblioteca C # que funciona bem para usá-lo em testes de unidade?

Crauscher
fonte
7
@Mark Seemann seria muito humilde em apontar isso, mas se você estiver interessado nesta questão, você deve pelo menos estar ciente de AutoFixture
Ruben Bartelink
1
Fala-se muito bem sobre a relação entre DI e mocking no Vimeo por Miguel Castro: vimeo.com/68390510
GregC 09/06/2014

Respostas:

131

De modo geral, um DI Container não deve ser necessário para o teste de unidade porque o teste de unidade trata da separação de responsabilidades.

Considere uma classe que usa injeção de construtor

public MyClass(IMyDependency dep) { }

Em todo o seu aplicativo, pode ser que haja um enorme gráfico de dependência oculto por trás IMyDependency, mas em um teste de unidade, você reduz tudo para um único Teste Duplo .

Você pode usar simulações dinâmicas como Moq ou RhinoMocks para gerar o Test Double, mas não é necessário.

var dep = new Mock<IMyDependency>().Object;
var sut = new MyClass(dep);

Em alguns casos, pode ser bom ter um contêiner de simulação automática , mas você não precisa usar o mesmo contêiner DI que o aplicativo de produção usa.

Mark Seemann
fonte
13
concordou ... a menos que um alvo de teste tenha um contêiner IoC como uma dependência, seus testes não deveriam precisar deles ... você irá remover a maior parte do gráfico do objeto quando fizer seus testes de unidade.
Anderson Imes
4
@Mark Seemann Isso faz sentido ... Mas e os testes de integração? Ou seja, brinquei com os testes de interface do usuário e me deparei com uma situação em que tive que compartilhar a raiz da composição. Algum comentário?
Arnis Lapsa
5
@Arnis L .: Para testes de integração é menos importante. Você pode escolher usar um DI Container para conectar os componentes, mas se assim for, é provável que você precise de uma configuração diferente para o container do que no aplicativo completo - a menos que você execute um Teste Subcutâneo ou um Teste de Sistema completo, neste caso você pode reutilizar a configuração do aplicativo do Container.
Mark Seemann
ref para a revista
msdn
18

Como um contêiner Ioc pode ser usado para testes de unidade?

IoC irá impor paradigmas de programação que tornarão o teste de unidade isoladamente (ou seja, usando simulações) mais fácil: uso de interfaces, sem new (), sem singletons ...

Mas usar o contêiner IoC para teste não é realmente um requisito, ele apenas fornecerá alguns recursos, por exemplo, injeção de simulações, mas você pode fazer isso manualmente.

É útil gerenciar mocks em uma solução enorme (mais de 50 projetos) usando IoC?

Não tenho certeza do que você quer dizer com gerenciamento de simulações usando IoC. De qualquer forma, os contêineres IoC geralmente podem fazer mais do que apenas injetar simulações quando se trata de testes. E se você tiver um suporte IDE decente que torne a refatoração possível, por que não usá-lo?

Alguma experiência?

Sim, em uma solução enorme, você precisa mais do que nunca de uma solução não sujeita a erros e adversa à refatoração (ou seja, por meio de um contêiner IoC seguro de tipo ou bom suporte IDE).

Pascal Thivent
fonte
17

Costumo usar um contêiner IoC em meus testes. É verdade que eles não são "testes de unidade" no sentido puro. IMO Eles são mais BDDish e facilitam a refatoração. Os testes existem para lhe dar confiança para refatorar. Testes mal escritos podem ser como colocar cimento em seu código.

Considere o seguinte:

[TestFixture]
public class ImageGalleryFixture : ContainerWiredFixture
{
    [Test]
    public void Should_save_image()
    {
        container.ConfigureMockFor<IFileRepository>()
            .Setup(r => r.Create(It.IsAny<IFile>()))
            .Verifiable();

        AddToGallery(new RequestWithRealFile());

        container.VerifyMockFor<IFileRepository>();
    }

    private void AddToGallery(AddBusinessImage request)
    {
        container.Resolve<BusinessPublisher>().Consume(request);
    }
}

Várias coisas acontecem ao adicionar uma imagem à galeria. A imagem é redimensionada, uma miniatura é gerada e os arquivos são armazenados no AmazonS3. Usando um contêiner, posso isolar mais facilmente apenas o comportamento que desejo testar, que, neste caso, é a parte persistente.

Uma extensão de contêiner de simulação automática é útil ao usar esta técnica: http://www.agileatwork.com/auto-mocking-unity-container-extension/

Mike Valenty
fonte
8
+1 para a frase "como derramar cimento em seu código". Comecei a usar o tempo todo.
Andrew Shepherd
2

Usando contêineres com capacidade para resolver serviços não registrados / desconhecidos como SimpleInjector , DryIoc (seu meu) pode retornar simulações para interfaces ainda não implementadas.

O que significa que você pode iniciar o desenvolvimento com a primeira implementação simples e suas dependências simuladas e substituí-las por coisas reais conforme você avança.

dadhi
fonte