Padrões de codificação de teste de unidade

22

Geralmente, quando se fala em padrões de codificação, nos referimos ao código do próprio programa, mas e os testes de unidade? Existem certas diretrizes de padrões de codificação exclusivas para testes de unidade? O que eles são?

EpsilonVector
fonte

Respostas:

12

De cabeça para baixo, consigo pensar em três diferenças no estilo de codificação do código de teste.

Nos métodos de teste de nomeação, sigo o padrão de shouldDoSomethingWhenSomeConditionHolds.

Dentro do teste, é habitual seguir o seguinte padrão de espaçamento:

@Test
shouldReturnAccountBalenceWhenGetBalenceIsCalled() {
    // Some lines 
    // of setup code
    // go here.

    // The action being tested happens after a blank line.

    // An assertion follows another blank line.
}

Alguns insistem em apenas uma afirmação por teste, mas isso está longe de ser universal.

O DRY (não se repita) é menos considerado no código de teste do que no código de produção. Enquanto algum código repetido deve ser colocado em um método setUp ou em uma classe testUtils, o esforço pela repetição zero no código de teste levará a testes fortemente acoplados e inflexíveis, o que desencoraja a refatoração.

Eric Wilson
fonte
Obviamente, há uma variedade de padrões, e é por isso que você também deve fornecer uma resposta.
Eric Wilson
10
Esse é o padrão Organizar, Agir, Afirmar .
precisa saber é o seguinte
SECO ainda é importante. Se você precisar fazer as mesmas declarações em vários testes, crie uma função comum e chame-a em todos os testes.
MiFreidgeim para de ser mau 30/11/17
@ MichaelFreidgeim Talvez estejamos falando apenas de graus, mas tenho uma tolerância significativamente maior à repetição no código de teste. Eu tive várias experiências de construção de suítes de testes com muito pouca repetição e descobri que os testes ficaram difíceis de modificar e entender quando os requisitos foram alterados. Depois, parei de me preocupar tanto com DRY nos testes, e minhas suítes de testes ficaram mais fáceis de usar. <shrug>
Eric Wilson
16

Roy Osherove recomenda o seguinte padrão para nomear seus testes:

NameOfMethodUnderTest_StateUnderTest_ExpectedBehavior() 

Consulte http://weblogs.asp.net/rosherove/archive/2005/04/03/TestNamingStandards.aspx

Robert Harvey
fonte
Eu concordo com o Roy. Além disso, melhora a legibilidade, eventhough ReSharper continua me dizendo que eu deveria removê-los para NameOfMethodUnderTestStateUnderTestExpectedBehavior();)
Oscar Mederos
Como fazer isso funcionar quando o método está sobrecarregado, para que haja vários métodos com o mesmo nome?
Narendra Pathai
6

O principal é lembrar que os testes de unidade são essencialmente mini-especificações. Isso significa que a ênfase deve sempre estar na legibilidade.

Em primeiro lugar, isso significa que os nomes devem comunicar claramente o que está sendo testado e o que está sendo afirmado.

Em segundo lugar, porém, que às vezes é esquecido, é que, como especificações, deveriam estar fazendo exatamente isso - especificando o comportamento. Ou seja, os testes de unidade não devem conter lógica - ou potencialmente caem na armadilha de repetir a funcionalidade do programa em vez de testá-la.

Às vezes, os testes envolvem objetos que são complexos de configurar, você deve manter essa lógica de configuração separada dos testes usando algo como uma mãe de objeto ou um construtor de dados de teste .

Vou terminar com algumas recomendações de livros:

Padrões de teste do xUnit: Código de teste da refatoração: Excelente livro, alguns dizem que está um pouco seco, mas acho que não. Apresenta muitos detalhes sobre várias maneiras diferentes de organizar testes e como mantê-los em manutenção. Relevante se você estiver usando algo como NUnit etc.

A arte do teste de unidade: com exemplos em .Net : o melhor livro sobre os detalhes da escrita e manutenção de testes. Apesar de realmente nova, acho que as seções de zombaria já estão um pouco datadas, já que a sintaxe AAA agora é bastante padrão, e não apenas outra maneira de fazê-lo.

Software Orientado a Objetos em Crescimento, Guiado por Testes : Este livro é incrível! De longe, o melhor livro de testes de unidade e o único avançado que coloca o teste de unidade como cidadão de primeira classe no processo de design. Estava lendo isso quando era uma versão beta pública e vinha recomendando desde então. Excelente exemplo de trabalho do mundo real usado ao longo do livro. Recomendaria a leitura do livro de Roy primeiro.

FinnNk
fonte
IMHO não há problema em testes unitários conterem lógica: é perfeitamente razoável testar uma versão altamente otimizada e eficiente de um algoritmo usando um algoritmo ingênuo que faz a mesma coisa para determinar o comportamento correto. Por exemplo, imagine testar uma tabela de hash criando um array associativo linear baseado em pesquisa.
dsimcha
2
Sim, mas isso pertence fora do teste nos construtores de dados de teste (que devem ser testados em unidade se a lógica dentro deles não for trivial). A exceção a isso seria bibliotecas de terceiros que geralmente são "confiáveis" para estarem corretas e podem ser usadas sem testes.
FinnNk
3

Não coloque lógica em seus testes de unidade. Por exemplo, digamos que você esteja testando um método add, você pode ter algo assim:

void MyTest_SaysHello()
{
   string name = "Bob";
   string expected = string.Format("Hello, {0}", name);
   IMyObjectType myObject = new MyObjectType();
   string actual = myObject.SayHello(name);
   Assert.AreEqual(expected, actual);
}

Nesse caso em particular, é provável que você repita a mesma lógica do que está no teste; portanto, você está essencialmente testando "1 + 1 == 1 + 1", em vez de "1 + 1 == 2", que é o teste "real". Então, como você realmente gostaria que seu código de teste fosse:

void MyTest_SaysHello()
{
   string expected = "Hello, Bob";
   IMyObjectType myObject = new MyObjectType();
   string actual = myObject.SayHello("Bob");
   Assert.AreEqual(expected, actual);
}
Hugo
fonte
2
Correção pequena: eu acho que você quis dizer 'seqüência de caracteres esperada = string.Format ("Olá, Bob")' deve ser 'seqüência de caracteres esperada = "Olá, Bob"'.
Mike Rosenblum
@MikeRosenblum você está obviamente certo, e alguém tentou corrigi-lo, mas dois revisores rejeitaram esta edição
Konrad Morawski
@ Konrad: isso é estranho. Este é um fórum de programação, certo?
9788 Mike
Editei a resposta mais uma vez, conforme sugerido por Mike Rosenblum.
precisa saber é
0

Nomes de métodos longos e descritivos. Lembre-se de que os métodos de teste nunca são chamados a partir do código (eles são chamados pelo executor de teste de unidade que os descobre e os chama por reflexão); portanto, não há problema em enlouquecer e ter nomes de métodos com 50 a 80 caracteres. Convenção de nomenclatura específica (caso de camelo, sublinhado, "deveria", "deve", "quando", "fornecido" etc.) não é realmente importante, desde que o nome responda a três perguntas:

  • o que está sob teste?
  • quais são as condições?
  • Qual é o resultado esperado?

Os métodos de teste devem ser curtos .

Os métodos de teste devem ter uma estrutura simples e linear . Não se ou construções de loop.

Os métodos de teste devem seguir o padrão "organizar-agir-afirmar" .

Cada teste deve testar uma coisa . Isso geralmente significa uma afirmação por teste. Um teste como { Do A; Assert B; Assert C; }deve ser refatorado em dois: { Do A; Assert B; }e{ Do A; Assert C; }

Evite dados aleatórios ou coisas como 'DateTime.Now'

Certifique-se de que todos os membros do equipamento de teste retornem ao seu estado original no final do teste (por exemplo, usando uma desmontagem )

Mesmo se você remover a duplicação sem piedade no seu código de produção, a duplicação de código nos equipamentos de teste é uma preocupação muito menor.

azheglov
fonte
-1

Um pouco semelhante ao que Farmboy já mencionou, Meu formato de nome de método

 <MethodName>Should<actionPerformed>When<Condition>

por exemplo

 GetBalanceShouldReturnAccountBalance() {
Amit Wadhwa
fonte