Teste de unidade: “É um cheiro de código se você está refatorando e não há colaboradores”?

9

Estou lendo A Arte do Teste de Unidade, de Roy Osherove. Estou na seção 7.2. Escrevendo testes de manutenção em que o autor tem essa observação sobre o cheiro do código:

NOTA: Quando você refatorar o estado interno para ser visível para um teste externo, ele poderá ser considerado um cheiro de código (um sinal de que algo pode estar errado no design ou na lógica do código)? Não é um cheiro de código quando você está refatorando para expor colaboradores. É um cheiro de código se você estiver refatorando e não houver colaboradores (para que você não precise stub ou zombar de nada).

EDIT : O que o autor quer dizer com "colaboradores" são dependências. Alguns de seus exemplos de dependências são classes que acessam um banco de dados ou que acessam o sistema de arquivos do sistema operacional. Aqui é onde ele define o stub e começa a usar a palavra colaborador:

Um stub é um substituto controlável para uma dependência (ou colaborador ) existente no sistema.

O autor não tem um exemplo desse cheiro de código e estou tendo problemas para entender / imaginar como isso seria. Alguém pode explicar isso um pouco mais e talvez fornecer um exemplo concreto?

programador
fonte
Eu acho que a confusão aqui decorre da palavra "Colaboradores". Devo admitir que também não tenho certeza do que ele quer dizer neste contexto.
Rossipedia 20/08/2012
@Bryan Ross, atualizei o post com a forma como o autor usa a palavra "colaborador". Obrigado!
programador

Respostas:

3

Eu acho que é isso que o autor está falando.

No meu exemplo de código, tenho uma janela de tempo que leva uma quantidade de saída mais um tempo de início e parada. A intenção é desenhar uma janela de saída em um período de 24 horas. Uma ruga é adicionada quando a hora de início é maior que a hora de parada, porque é uma janela de tempo que se estende à meia-noite.

Você pode escrever testes de unidade que exercitam completamente o objeto sem expor as variáveis ​​privadas. Esses bools e intervalos de tempo particulares são os colaboradores a que ele se refere ao expor os internos para testes de unidade. De acordo com o livro, expor esses internos NÃO seria um cheiro de código, pois eles são colaboradores.

Expor o double outputseria um cheiro de código, já que não é um colaborador - é um elemento explicitamente oculto pela própria classe que possui lógica condicional GetOutputpara determinar o que deve ser retornado.

A escavação nos bools / timespans tornaria os testes de unidade mais abrangentes. Ele diz que isso é bom.
Escavar para o dobro outputexigiria lógica adicional no seu teste de unidade que espelhava o que GetOutputestava fazendo. Este seria o cheiro do código ao qual ele está se referindo.

classe pública TimeWindow
{
  bool privado isConst;
  private bool spansMidnight;
  TimeSpan privado start1;
  TimeSpan privado stop1;
  TimeSpan privado start2;
  TimeSpan privado stop2;
  saída dupla privada;

  TimeWindow público (duplicação, início do TimeSpan, parada do TimeSpan)
  {
    saída = saída;

    if (iniciar == parar)
      isConst = true;
    caso contrário, se (iniciar> parar)
    {
      spansMidnight = true;
      start1 = meia-noite;
      stop1 = parada;
      start2 = iniciar;
      stop2 = meia-noite;
    }
    outro 
    {
      start1 = iniciar;
      stop1 = parada;
    }
  }

  public double GetOutput (TimeSpan time)
  {
    // alguma lógica aqui sobre o que / como retornar
    ...
    retorno de saída;
  }

}

fonte
0

Digamos que temos uma classe de domínio, e essa classe de domínio tem conhecimento direto da camada de persistência usando um Repositório, que ele usa para expor um método "Salvar" no nível da instância que objetos que trabalham na classe de domínio podem chamar para persistir alterações feita sem a necessidade de conhecimento do mecanismo (se esse é um design "bom" é uma discussão para outro dia). Refatorar a classe para expor esse Repositório como uma propriedade e / ou argumento do construtor, permitindo que um Repositório zombado seja passado para garantir que a chamada adequada seja feita, normalmente é uma coisa boa não apenas para teste, mas também para manutenção geral.

Agora, por ser uma classe de domínio, ela possui dados de estado. Vamos supor por um momento que uma das propriedades com estado possui um campo de apoio e os acessadores de propriedades testam que uma nova entrada é válida com base na atual (talvez o novo valor nunca possa ser menor que o antigo). Você precisa testar essa validação, mas acha que isso exige acesso ao campo de suporte para definir um valor inicial que você tentará sobrescrever. Isso deve ser uma bandeira vermelha; se o teste precisar de acesso ao campo de apoio (que é um detalhe da implementação; nenhum consumidor deve jamaisprecisa saber que está lá) para colocar o objeto em um estado consistente para um teste, então como o código de produção obteria um objeto consistente? Se houver um método para o código de produção fazer a mesma coisa que o seu teste, então o teste provavelmente deve imitar dessa maneira. Se não há uma maneira válida para o código de produção colocar o objeto nesse estado, por que você está testando esse cenário?

KeithS
fonte