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?
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?
Respostas:
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.
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
NameOfMethodUnderTestStateUnderTestExpectedBehavior()
;)
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.
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);
}
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:
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.
Um pouco semelhante ao que Farmboy já mencionou, Meu formato de nome de método
<MethodName>Should<actionPerformed>When<Condition>
por exemplo
GetBalanceShouldReturnAccountBalance() {