Pergunta

Por exemplo, eu estou escrevendo testes contra um CSVReader. É uma classe simples que enumera e divide linhas de texto. Sua única raison d'être está ignorando vírgulas dentro de aspas. É menos do que uma página.

Por "caixa preta" testar a classe, eu verifiquei coisas como

  • O que se o arquivo não existe?
  • E se eu não tenho permissão no arquivo?
  • O que acontece se o arquivo tem não Windows quebras de linha?

Mas, na verdade, todas estas coisas são o negócio da StreamReader. Minha classe funciona sem fazer nada sobre esses casos. Então, em essência, meus testes estão a recuperar erros lançados por StreamReader, e testar o comportamento tratado pelo framework. Parece um monte de trabalho para nada.

Eu vi as questões relacionadas

A minha pergunta é, estou faltando o ponto de "caixa de vidro" testar se eu usar o que sei para evitar este tipo de trabalho?

Foi útil?

Solução

Isso realmente depende da interface do seu CSVReader, você precisa considerar o que o usuário da classe está esperando.

Por exemplo, se um dos parâmetros é um nome de arquivo e o arquivo não existe o que deve acontecer? Isso não deve ser dependente se você usar um leitor de fluxo ou não. Os testes de unidade devem testar o comportamento externo observável da sua classe e, em alguns casos, para cavar um pouco mais profunda e, adicionalmente, garantir certos detalhes de implementação são cobertos, por exemplo, o arquivo é fechado quando o leitor termina.

No entanto, você não quer que a Unidade de testes para ser dependente de todos os detalhes ou para supor que por causa de um detalhe de implementação algo vai acontecer.

Todos os exemplos que você menciona na sua pergunta envolvem comportamento observável (neste caso, circunstâncias excepcionais) de sua classe e, portanto, deve ter testes unitários relacionados a eles.

Outras dicas

Eu não acho que você deve perder tempo testando coisas que não são o seu código. É uma escolha de design, não uma escolha de testes, seja para lidar com os erros da estrutura subjacente ou deixá-los propagar-se para o chamador. FWIW, eu acho que você está certo para deixá-los propagar-se. Uma vez que você tomou a decisão de projeto, no entanto, o seu teste de unidade deve cobrir o seu código (e cobri-lo bem) sem testar a estrutura subjacente. Usando dependência injeção e um fluxo de simulação é provavelmente uma boa idéia também.

[EDIT] Exemplo de injecção de dependência (ver link acima para obter mais informação)

Não usar injeção de dependência que temos:

public class CvsReader {
   private string filename;
   public CvsReader(string filename)
   {
      this.filename = filename;
   }

   public string Read()
   {
      StreamReader reader = new StreamReader( this.filename );
      string contents = reader.ReadToEnd();
      .... do some stuff with contents...
      return contents;
   }
}

Com a injeção de dependência (injeção de construtor) que fazemos:

public class CvsReader {
   private IStream stream;
   public CvsReader( IStream stream )
   {
      this.stream = stream;
   }

   public string Read()
   {
       StreamReader reader = new StreamReader( this.stream );
       string contents = reader.ReadToEnd();
       ...  do some stuff with contents ...
       return contents;
   }
}

Isso permite que o CvsReader ser mais facilmente testável. Nós passar uma instância da implementação da interface dependemos no construtor, neste caso IStream. Devido a isso, podemos criar uma outra classe (talvez uma classe falsa) que implementa IStream, mas não necessariamente fazer arquivo de I / O. Podemos usar essa classe para alimentação ao nosso leitor todos os dados que nós queremos sem envolver qualquer do quadro subjacente. Neste caso, eu usaria um MemoryStream, uma vez que apenas ler a partir dele. Em queríamos, embora, poderíamos usar uma classe falsa e dar-lhe uma interface mais rica que permite que nossos testes configurar as respostas que ele dá. Desta forma, podemos testar o código que nós escrevemos e não envolver o código do framework subjacente em tudo. Alternativamente, também pode passar um TextReader, mas o padrão de injeção de dependência normal, utiliza interfaces e eu queria mostrar o padrão com interfaces. Indiscutivelmente passando um TextReader seria melhor uma vez que o código acima ainda é dependente da implementação StreamReader.

Sim, mas isso seria estritamente ser para fins de teste de unidade:

Você poderia abstrato implementação seu leitor CSV a partir de qualquer StreamReader nomeadamente através da definição de uma interface abstrata leitor de fluxo e testar sua própria implementação com um leitor de fluxo de simulação que implementa essa interface. Seu leitor falsa, obviamente, seria imune a erros como arquivos inexistentes, problemas de permissão, as diferenças de sistema operacional etc. Você teria, portanto, inteiramente ser testando seu próprio código e pode alcançar a cobertura de código 100%.

Eu tendo a concordar com tvanfosson: Se você herdar de um StreamReader e estendê-lo de alguma forma, os testes de unidade só deve exercer a funcionalidade que você adicionou ou alterado. Caso contrário, você vai perder muito tempo e escrita energia cognitiva, leitura e manutenção de testes que não acrescentam qualquer valor.

Embora markj é correto que os testes devem cobrir o "comportamento externo observável" de uma classe, eu acho que é apropriado considerar , onde que o comportamento vem. Se seu comportamento através de herança de outro (presumivelmente unidade testada) classe, então não vejo benefício em adicionar seu próprio unidade testes. OTOH, se é comportamento via composição, em seguida, pode justificar alguns testes para assegurar que os repasses estão funcionando corretamente.

A minha preferência seria para teste de unidade a funcionalidade específica que você alterar, e em seguida, escrever Integração testes que verificam as condições de erro, mas no contexto da necessidade de negócio você está, em última instância de apoio.

Apenas um FYI, se este for .NET, você deve considerar não reinventar a roda.

Para C #

Adicione uma referência para Microsoft.VisualBasic Use o Microsoft.VisualBasic.FileIO.TextFieldParser classe fantástica () para lidar com as suas necessidades de CSV análise.

A Microsoft já testei, assim você não terá que.

Aproveite.

Você deve sempre ser gerir erros que o seu quadro lança; Dessa forma, sua aplicação é robusta e não falhar em erros catastróficos ...

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