Pergunta

A fim de ajudar o meu código testável equipe de gravação, eu vim com esta simples lista de melhores práticas para tornar a nossa base de código C # mais testável. (Alguns dos pontos referem-se a limitações de Rhino Mocks, um quadro zombando para C #, mas as regras podem ser aplicadas de forma mais geral, bem.) Alguém tem alguma melhores práticas que eles seguem?

Para maximizar a capacidade de teste de código, siga estas regras:

  1. escrever o teste primeiro, depois o código Motivo:.. Isso garante que você escrever código testável e que cada linha de código obtém testes escritos para ele

  2. classes de design usando a injeção de dependência Motivo:.. Você não pode zombar ou teste que não pode ser visto

  3. código UI separado do seu comportamento usando MVC ou Model-View-Presenter Motivo:. Permite que a lógica de negócios a ser testado enquanto as partes que não podem ser testadas (UI) é minimizado.

  4. Não escreva métodos estáticos ou classes Motivo:.. Os métodos estáticos são difíceis ou impossíveis de isolar e Rhino Mocks é incapaz de zombar deles

  5. Programa off interfaces, não as classes . Razão: o uso de interfaces esclarece as relações entre os objetos. Uma interface deve definir um serviço que um objeto precisa do seu ambiente. Além disso, as interfaces podem ser facilmente ridicularizado usando Rhino Mocks e outros frameworks de zombaria.

  6. <> fortes dependências externas Isolar Motivo:.. Dependências externo não resolvido não pode ser testada

  7. Mark como virtual os métodos que pretendem zombar Motivo:.. Rhino Mocks é incapaz de zombar métodos não-virtuais

Foi útil?

Solução

Definitivamente uma lista boa. Aqui estão alguns pensamentos sobre isso:

escrever o teste primeiro, depois o código.

Eu concordo, a um nível elevado. Mas, eu seria mais específico: "Escrever um teste em primeiro lugar, em seguida, escrever apenas o suficiente código para passar no teste, e repita." Caso contrário, eu estaria com medo de que meus testes de unidade ficaria mais como testes de integração ou de aceitação.

classes de design usando a injeção de dependência.

De acordo. Quando um objeto cria suas próprias dependências, você não tem controle sobre eles. Inversão de controle / Dependência de injecção dá-lhe que o controlo, o que lhe permite isolar o objecto em teste com as simulações / topos / etc. Isto é como você testar objetos em isolamento.

código UI separado do seu comportamento usando MVC ou Model-View-Presenter.

De acordo. Note-se que mesmo o apresentador / controlador pode ser testado usando DI / COI, pela entrega que um stubados / vista escarnecido e modelo. Confira Apresentador Primeira TDD para saber mais sobre isso.

Do métodos estáticos não escrita ou classes.

Não tenho certeza eu concordo com este. É possível teste de unidade de um método / classe estática sem o uso de simulações. Então, talvez esta seja uma daquelas regras específicas Rhino Mock que você mencionou.

Programa off interfaces, não classes.

Eu concordo, mas por uma razão um pouco diferente. Interfaces fornecer uma grande quantidade de flexibilidade para o desenvolvedor de software - além do apoio apenas para vários quadros de objeto fictício. Por exemplo, não é possível apoiar DI corretamente sem interfaces.

dependências externas Isolar.

De acordo. Esconder dependências externas por trás de sua própria fachada ou adaptador (conforme o caso) com uma interface. Isso permitirá que você isolar o seu software a partir da dependência externa, seja um serviço web, uma fila, um banco de dados ou qualquer outra coisa. Esta é especialmente importante quando sua equipe não controla a dependência (A.K.A. externo).

Mark como virtual os métodos que pretendem zombar.

Isso é uma limitação do Rhino Mocks. Em um ambiente que prefere codificadas manualmente tocos sobre um quadro objeto fictício, isso não seria necessário.

E, um par de novos pontos a considerar:

Usar padrões de projeto criacionais. Isso vai ajudar com DI, mas também permite isolar esse código e testá-lo independentemente de outra lógica.

testes escrever usando Bill Wake está Organizar / Lei / Assert técnica . Esta técnica deixa muito claro qual configuração é necessária, o que realmente está sendo testado, e que é esperado.

Do not ter medo de rolar suas próprias simulações / tocos. Muitas vezes, você verá que utilizando frameworks objeto fictício faz seus testes muito difícil de ler. Rolando seu próprio país, você terá o controle completo sobre suas zomba / tocos, e você será capaz de manter seus testes legível. (Consulte de volta ao ponto anterior).

Evite a tentação de duplicação refactor fora de seus testes de unidade em classes abstratas de base, ou configuração / métodos de desmontagem. Se o fizer, peles código de configuração / clean-up do desenvolvedor tentando Grokar o teste de unidade . Neste caso, a clareza de cada teste individual é mais importante do que a refatoração a duplicação.

Implementar Integração Contínua. Entrada seu código em cada "barra verde". Construa o seu software e executar o seu conjunto completo de testes de unidade em cada check-in. (Claro, isso não é uma prática de codificação, per se; mas é uma ferramenta incrível para manter seu software limpo e totalmente integrado.)

Outras dicas

Se você está trabalhando com .Net 3.5, você pode querer olhar para a biblioteca Moq zombeteiro -. ele usa árvores de expressão e lambdas para remover não-intuitiva expressão registro de resposta da maioria das outras bibliotecas zombaria

Confira este quickstart para ver como muito mais intuitivo seus casos de teste tornar-se, aqui está um exemplo simples:

// ShouldExpectMethodCallWithVariable
int value = 5;
var mock = new Mock<IFoo>();

mock.Expect(x => x.Duplicate(value)).Returns(() => value * 2);

Assert.AreEqual(value * 2, mock.Object.Duplicate(value));

Saiba a diferença entre falsificações, simulações e topos e quando usar cada um.

Evitar o excesso especificando interações usando simulações. Isto faz testes frágil .

Este é um post muito útil!

Gostaria de acrescentar que é sempre importante para compreender o contexto e Teste Em Sistema (SUT). Após diretores TDD para a letra é muito mais fácil quando você está escrevendo novo código em um ambiente onde o código existente segue os mesmos princípios. Mas quando você está escrevendo novo código em um ambiente não TDD legado você achar que seus esforços TDD pode balão rapidamente muito além de suas estimativas e expectativas.

Para alguns de vocês, que vivem em um mundo totalmente acadêmica, prazos e entrega pode não ser importante, mas em um ambiente onde software é dinheiro, fazendo uso eficaz de seu esforço TDD é crítica.

TDD é altamente sujeita à Lei de Diminutiva Marginal Retorno . Em suma, os seus esforços no sentido de TDD são cada vez mais valioso até atingir um ponto de máximo retorno, após o qual, o tempo posterior investido em TDD tem cada vez menos valor.

I tendem a acreditar que o valor principal do TDD é no limite (caixa preta), bem como no teste de caixa-branca ocasional de áreas críticas do sistema.

A verdadeira razão para a programação contra interfaces não é para a vida make mais fácil para Rhino, mas para esclarecer as relações entre os objetos no código. Uma interface deve definir um serviço que um objeto precisa do seu ambiente. A classe fornece uma implementação específica desse serviço. O livro de leitura Rebecca Wirfs-Brock "Objeto Design" em funções, responsabilidades e colaboradores.

Boa lista. Uma das coisas que você pode querer estabelecer - e eu não posso dar-lhe muitos conselhos desde que eu estou apenas começando a pensar sobre ele próprio - é quando uma classe deve estar em uma biblioteca diferente, namespace, namespaces aninhados. Você pode até querer descobrir uma lista de bibliotecas e espaços de nomes de antemão e mandato que a equipe tem de conhecer e decidir fundir dois / adicionar um novo.

Oh, só pensava em algo que eu faço que você pode querer também. Eu geralmente têm uma biblioteca de testes de unidade com um dispositivo de ensaio por política de classe em que cada teste entra em um namespace correspondente. Eu também tendem a ter uma outra biblioteca de testes (testes de integração?), Que é de uma forma mais BDD estilo . Isso me permite testes de gravação para spec que o método deve fazer, bem como o que a aplicação deve fazer em geral.

Aqui está um outro que eu pensei de que eu gosto de fazer.

Se você pretende executar testes do teste de unidade Gui em oposição a partir TestDriven.Net ou NAnt então eu achei mais fácil de configurar a unidade testar tipo de projeto de aplicativo de console, em vez de biblioteca. Isso permite que você execute testes manualmente e passo por eles no modo de depuração (que o TestDriven.Net acima mencionado pode realmente fazer por você).

Além disso, eu sempre gosto de ter um projeto Parque aberta para testar pedaços de código e idéias que eu estou familiarizado com. Isso não deve ser verificado no controle de origem. Mesmo melhor, ele deve estar em um repositório de controle de fonte separada na máquina do desenvolvedor só.

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