métodos de teste de unidade de fábrica que têm uma classe concreta como um tipo de retorno

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

  •  21-08-2019
  •  | 
  •  

Pergunta

Então, eu tenho uma classe de fábrica e eu estou tentando descobrir o que os testes de unidade deve fazer. A partir desta questão pude verificar que a interface retornado é de um tipo concreto particular que eu esperaria.

O que devo verificar se a fábrica está retornando tipos de concreto (porque não há necessidade - no momento - para interfaces para ser usado)? Atualmente eu estou fazendo algo como o seguinte:

[Test]
public void CreateSomeClassWithDependencies()
{
    // m_factory is instantiated in the SetUp method
    var someClass = m_factory.CreateSomeClassWithDependencies();

    Assert.IsNotNull(someClass);
}

O problema com isto é que o Assert.IsNotNull parece um pouco redundante.

Além disso, o meu método de fábrica pode ser configurar as dependências de que determinada classe assim:

public SomeClass CreateSomeClassWithDependencies()
{
    return new SomeClass(CreateADependency(), CreateAnotherDependency(),
                         CreateAThirdDependency());
}

E eu quero ter certeza de que meu método de fábrica configura todas estas dependências corretamente. Não há outra maneira de fazer isso, em seguida, para fazer essas propriedades dependências public/internal que eu então verificar no teste de unidade? (Eu não sou um grande fã de modificar os assuntos de teste de acordo com o teste)

Edit: Em resposta à pergunta de Robert Harvey, estou usando NUnit como meu framework de testes unitários (mas eu não teria pensado que iria fazer muito de uma diferença)

Foi útil?

Solução

Muitas vezes, não há nada errado com a criação de propriedades públicas que podem ser usados ??para o teste baseado no estado. Sim: É o código que você criou para habilitar um cenário de teste, mas dói a sua API? É concebível que outros clientes iria encontrar a mesma propriedade útil mais tarde?

Há uma linha tênue entre o código específico de teste e Teste-Driven projeto. Não devemos introduzir o código que não tem outro potencial do que para satisfazer uma exigência de teste, mas é bastante bom para introduzir um novo código que seguem geralmente aceite os princípios de design. Deixamos o teste unidade nosso projeto - que é por isso que chamamos TDD:)

Como adicionar uma ou mais propriedades para uma classe para dar ao usuário uma melhor possibilidade de inspecionar essa classe é, na minha opinião, muitas vezes uma coisa razoável a fazer, então eu não acho que você deve descartar a introdução de tais propriedades.

Além disso, eu segunda resposta de Nader:)

Outras dicas

Se a fábrica está retornando tipos de concreto, e você está garantindo que a sua fábrica sempre retorna um tipo concreto, e não nulo, então não, não é muito muito valor no teste. Ele permite que você certifique-se, ao longo do tempo que essa expectativa não é violada, e coisas como exceções não são lançadas.

Este estilo de teste simplesmente garante que, como você fazer mudanças no futuro, o seu comportamento fábrica não vai mudar sem você saber.

Se o seu idioma suporta, para as suas dependências, você pode usar a reflexão. Isso nem sempre é o mais fácil de manter, e casais seus testes muito firmemente a sua implementação. Você tem que decidir se isso é aceitável. Esta abordagem tende a ser muito frágil.

Mas você realmente parece estar tentando separar quais classes são construídos, de como os construtores são chamados. Você pode apenas ser melhor fora com o uso de um quadro DI para obter esse tipo de flexibilidade.

Por new-ing todos os seus tipos como você precisa deles, você não dar-se muitas costuras (a emenda é um lugar onde você pode alterar o comportamento em seu programa sem editar naquele lugar) para trabalhar.

Com o exemplo que você dá-lo, porém, você pode derivar uma classe de fábrica. Então substituição / CreateADependency() simulada, CreateAnotherDependency() e CreateAThirdDependency(). Agora quando você chamar CreateSomeClassWithDependencies(), você é capaz de sentido ou não as dependências corretas foram criadas.

Nota: a definição de "costura" vem do livro de Michael Pena, "trabalhar efetivamente com Legacy Code". Ele contém exemplos de muitas técnicas para adicionar capacidade de teste de código não testado. Você pode achar que é muito útil.

O que fazemos é criar as dependências com as fábricas, e nós usamos um quadro injeção de dependência para substituir fábricas simulados para os reais quando o teste é executado. Então montamos as expectativas apropriadas sobre essas fábricas simulados.

Você pode sempre verificar o material com reflexão. Não há necessidade de expor algo apenas para testes de unidade. Acho que é bastante raro que eu preciso para chegar em com reflexão e isso pode ser um sinal de design ruim.

Olhando para o seu código de exemplo, sim o Assert não nulo parece redundante, dependendo da maneira que você projetou sua fábrica, alguns vão retornar objetos nulos da fábrica ao contrário exceptioning fora.

Pelo que entendi você quer teste que as dependências são construídos corretamente e passou para a nova instância?

Se eu não era capaz de usar um quadro como o Google Guice, eu provavelmente faria algo assim (aqui usando JMock e Hamcrest):

@Test
public void CreateSomeClassWithDependencies()
{
    dependencyFactory = context.mock(DependencyFactory.class);
    classAFactory = context.mock(ClassAFactory.class);

    myDependency0 = context.mock(MyDependency0.class);
    myDependency1 = context.mock(MyDependency1.class);
    myDependency2 = context.mock(MyDependency2.class);
    myClassA = context.mock(ClassA.class);

    context.checking(new Expectations(){{
       oneOf(dependencyFactory).createDependency0(); will(returnValue(myDependency0));
       oneOf(dependencyFactory).createDependency1(); will(returnValue(myDependency1));
       oneOf(dependencyFactory).createDependency2(); will(returnValue(myDependency2));

       oneOf(classAFactory).createClassA(myDependency0, myDependency1, myDependency2);
       will(returnValue(myClassA));
    }});

    builder = new ClassABuilder(dependencyFactory, classAFactory);

    assertThat(builder.make(), equalTo(myClassA));
}

(se você não pode simulada ClassA é possível atribuir uma versão não-simulada para myClassA usando novo)

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