Práticas recomendadas para nomeação de teste de unidade [fechado]

564

Quais são as práticas recomendadas para nomear classes de teste de unidade e métodos de teste?

Isso foi discutido anteriormente no SO, em Quais são algumas convenções de nomenclatura populares para testes de unidade?

Não sei se essa é uma abordagem muito boa, mas atualmente em meus projetos de teste, tenho mapeamentos individuais entre cada classe de produção e uma classe de teste, por exemplo, Producte ProductTest.

Nas minhas aulas de teste, tenho métodos com os nomes dos métodos que estou testando, um sublinhado e, em seguida, a situação e o que espero que aconteça, por exemplo Save_ShouldThrowExceptionWithNullName().

James Newton-King
fonte
Veja aqui: stackoverflow.com/questions/96297/…
Ponto e vírgula esquecido
1
Isso não responder à sua pergunta, mas vale a pena ler: haacked.com/archive/2012/01/02/structuring-unit-tests.aspx
Robs
3
O guia de estilo do Google diz :,test<MethodUnderTest>_<state> por exemplo, testPop_emptyStack google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Nomes dos métodos. Em caso de dúvida, siga o Google.
Ciro Santilli respondeu
2
@CiroSantilli 轩 事件 法轮功 包 卓 E a próxima frase diz: "Não existe uma maneira correta de nomear métodos de teste". Vai saber.
precisa saber é o seguinte
1
Ainda prefiro a recomendação de Phil Haack, mesmo anos depois.
pimbrouwers 17/09/18

Respostas:

524

Gosto da estratégia de nomes de Roy Osherove , é a seguinte:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Possui todas as informações necessárias sobre o nome do método e de maneira estruturada.

A unidade de trabalho pode ser tão pequena quanto um único método, uma classe ou tão grande quanto várias classes. Ele deve representar todas as coisas que devem ser testadas neste caso de teste e estão sob controle.

Para montagens, uso o .Testsfinal típico , que eu acho bastante difundido e o mesmo para as classes (terminando com Tests):

[NameOfTheClassUnderTestTests]

Anteriormente, usei o Fixture como sufixo em vez de testes, mas acho que o último é mais comum, depois mudei a estratégia de nomeação.

Marc Climent
fonte
228
Para mim, não faz sentido colocar o nome do método no método de teste. E se você renomear o método? Nenhuma ferramenta de refatoração renomeará testes para você. Eventualmente, você acaba renomeando os métodos de teste manualmente ou, mais provavelmente, com testes nomeados incorretamente. É como nos comentários. Muito é pior do que não comentar o código.
Piotr Perak 29/05
80
@ Peri, acho que é uma troca. Por um lado, seus nomes de teste podem ficar desatualizados; por outro, você não pode dizer qual método está testando. Acho que o último aparece com muito mais frequência.
Joel McBeth
15
Para adicionar ao comentário do Peri - todos os métodos são responsáveis ​​por alguma ação, por exemplo UpdateManager.Update(). Tendo isso em mente, costumo chamar meus testes WhenUpdating_State_Behaviourou WhenUpdating_Behaviour_State. Dessa forma, testo uma ação específica de uma classe, evitando colocar um nome de método em um nome de teste. Mas o mais importante é que eu tenho que ter uma idéia de que lógica de negócios está falhando quando vejo o nome de um teste que falhou.
Ramunas
8
O Resharper e o IntelliJ provavelmente encontrariam seu método de teste e se ofereceriam para renomeá-lo se você refatorasse / renomeie usando essas ferramentas. Também tente procurar nos comentários em que você menciona o nome do método e atualize-os também.
Jeff Martin
62
Os bons nomes de métodos geralmente são os mesmos da ação realizada pelo método. Se você tiver que decidir entre nomear seu teste após o método ou a ação que o método executa, que pode ser uma dica, renomeie o método . (Não em todos os casos)
Kaadzia 19/09/13
121

Eu gosto de seguir o padrão de nomeação "Deveria" para testes enquanto nomeava o dispositivo de teste após a unidade em teste (ou seja, a classe).

Para ilustrar (usando C # e NUnit):

[TestFixture]
public class BankAccountTests
{
  [Test]
  public void Should_Increase_Balance_When_Deposit_Is_Made()
  {
     var bankAccount = new BankAccount();
     bankAccount.Deposit(100);
     Assert.That(bankAccount.Balance, Is.EqualTo(100));
  }
}

Por que "deveria" ?

Acho que isso força os autores do teste a nomearem o teste com uma frase como "Deve [estar em algum estado] [depois / antes / quando] [a ação ocorre]"

Sim, escrever "Deveria" em todos os lugares fica um pouco repetitivo, mas como eu disse, obriga os escritores a pensar da maneira correta (o que pode ser bom para iniciantes). Além disso, geralmente resulta em um nome de teste de inglês legível.

Atualização :

Percebi que Jimmy Bogard também é fã de 'should' e até tem uma biblioteca de testes de unidade chamada Should .

Atualização (4 anos depois ...)

Para os interessados, minha abordagem para nomear testes evoluiu ao longo dos anos. Um dos problemas com o padrão Should , descrito acima, não é fácil saber rapidamente qual método está sendo testado. Para OOP, acho que faz mais sentido iniciar o nome do teste com o método em teste. Para uma classe bem projetada, isso deve resultar em nomes de métodos de teste legíveis. Agora eu uso um formato semelhante a <method>_Should<expected>_When<condition>. Obviamente, dependendo do contexto, você pode substituir os verbos Dever / Quando por algo mais apropriado. Exemplo: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

Jack Ukleja
fonte
32
Talvez ainda melhor e menos redundantes, basta escrever uma frase que diz que ele faz, assumindo as obras de teste: increasesBalanceWhenDepositIsMade().
Hotshot309
3
Recentemente, vi um artigo que mencionava uma convenção de nomenclatura semelhante (gostaria de ter marcado isso). Projetado para tornar as listas de testes muito legíveis quando classificadas por equipamento de teste. Você vê algo como "BankAccount", abaixo dele (em linhas diferentes) "Should_Increase_Balance_When_Deposit_Is_Made" "Should_Decrease_Balance_When_Withdrawal_Is_Made" etc.
Simon Tewsi
Encontrei o artigo. Está no blog CodeThinked, de Justin Etheredge, Começando com o Moq 3 - Parte 1 .
Simon Tewsi
11
Eu também uso Should e When, mas o contrário. por exemplo, WhenCustomerDoesNotExist_ShouldThrowException (). Para mim, isso faz muito mais sentido do que deveria então quando (ou seja, em um determinado cenário, deve haver um certo resultado esperado). Isso também se encaixa com AAA (Organizar, Agir, Assert) ... o Assert é no final ... não o começo ;-)
bytedev
2
@ Schneider: considerando "deveria" = "recomendado", então opcional, pergunto-me: não seria lexicalmente melhor usar "deve" = "deve" então necessário / obrigatório. Por exemplo, os RFCs fazem a diferença entre ambos. Portanto, ter aprovação nos testes é recomendado ou necessário?
blackwizard
79

Eu gosto deste estilo de nomeação:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

e assim por diante. Isso deixa muito claro para quem não faz o teste qual é o problema.

Sklivvz
fonte
63
mas @ hotshot309, ele pode estar usando .NET - Convenções de Capitalização .NET
Ace
2
@ Ace, eu concordo totalmente com você e notei isso cerca de um minuto depois que eu postei este comentário. Jurei que o apaguei quando vi meu erro, mas de alguma forma, acho que não. Me desculpe por isso.
Hotshot309 13/03/12
3
@CoffeeAddict porque sublinhados dentro identificadores são uma <del> aberração </ del> realmente não idiomática em C #
Sklivvz
2
Eu também gostaria de evitar o uso de shouldI preferem willassimOrdersWithNoProductsWillFail()
Calin
4
@Calin Na minha opinião, o uso Willnão é realmente apropriado e, ao fazê-lo, você está dizendo ao leitor por engano que de forma alguma o teste falhará ... se você Willexpressar algo no futuro que pode não acontecer, você estará usá-lo incorretamente. Considerando que Shouldé a melhor opção aqui, porque indica que você deseja / deseja que algo aconteça, mas não aconteceu ou não, quando o teste é executado, ele diz se falhou / teve êxito, então você não pode realmente sugerir que de antemão, essa é a explicação lógica, qual é a sua? por que você evita Should?
Eyal Solnik
51

Kent Beck sugere:

  • Um dispositivo de teste por 'unidade' (classe do seu programa). Os equipamentos de teste são as próprias classes. O nome do dispositivo de teste deve ser:

    [name of your 'unit']Tests
    
  • Os casos de teste (os métodos dos equipamentos de teste) têm nomes como:

    test[feature being tested]
    

Por exemplo, tendo a seguinte classe:

class Person {
    int calculateAge() { ... }

    // other methods and properties
}

Um acessório de teste seria:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}
Sergio Acosta
fonte
4
Eu gostaria que mais pessoas seguissem essas diretrizes. Há pouco tempo, tive que renomear mais de 20 métodos de teste porque eles tinham nomes como "ATest", "BasicTest" ou "ErrorTest".
04 de
85
o prefixo do método 'test' não se torna redundante devido ao sufixo da classe?
Gavin Miller
50
Lembre-se disso quando Kent escreveu esse livro. Os atributos não foram inventados. Portanto, o nome Teste no nome do método indicava para a estrutura de teste que o método era um teste. Também muita coisa aconteceu desde 2002.
Thomas Jespersen
14
testCalculateAge ... esse é um nome sem sentido para o seu método de teste. "test" é redundante (você nomeia todos os seus métodos com o prefixo "method"?). O restante do nome não tem condição em teste ou o que era esperado. CalculateAge é o método em teste ..... quem sabe ...?
bytedev
1
Eu gostaria de acrescentar que, ao usar esta estratégia, é necessária documentação para especificar a saída esperada. Como uma observação lateral sobre o prefixo 'test'; algumas estruturas de teste de unidade requerem prefixos ou sufixos específicos para reconhecer os testes. O prefixo de classes abstratas com 'Abstract' não é considerado redundante (porque é auto-documentado); então, por que o mesmo não se aplica a 'Test'?
siebz0r
17

Nomes de classe . Para nomes de acessórios de teste, acho que "Teste" é bastante comum na linguagem onipresente de muitos domínios. Por exemplo, em um domínio de engenharia: StressTeste em um domínio de cosméticos: SkinTest. Desculpe discordar de Kent, mas usar "Teste" em meus equipamentos de teste ( StressTestTest?) É confuso.

"Unidade" também é muito usado em domínios. Por exemplo MeasurementUnit. É uma classe chamadaMeasurementUnitTest teste de "Measurement" ou "MeasurementUnit"?

Portanto, eu gosto de usar o prefixo "Qa" para todas as minhas classes de teste. Por exemplo, QaSkinTeste QaMeasurementUnit. Nunca é confundido com objetos de domínio, e usar um prefixo em vez de um sufixo significa que todos os equipamentos de teste vivem juntos visualmente (útil se você tiver falsificações ou outras classes de suporte em seu projeto de teste)

Namespaces . Trabalho em C # e mantenho minhas classes de teste no mesmo espaço para nome da classe que eles estão testando. É mais conveniente do que ter espaços para nome de teste separados. Obviamente, as classes de teste estão em um projeto diferente.

Teste os nomes dos métodos . Eu gosto de nomear meus métodos WhenXXX_ExpectYYY. Isso torna clara a pré-condição e ajuda na documentação automatizada (à la TestDox). Isso é semelhante ao conselho do blog de testes do Google, mas com mais separação de pré-condições e expectativas. Por exemplo:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory
grundoon
fonte
você falou sobre nomes de métodos de teste e nomes de aparelhos de teste. os nomes dos equipamentos de teste são mapeados para as classes de produção. onde você escreve o nome do método de produção em seu teste?
The Light
12

Eu uso o conceito Given-When-Then . Dê uma olhada neste pequeno artigo http://cakebaker.42dh.com/2009/05/28/given-when-then/ . O artigo descreve esse conceito em termos de BDD, mas você pode usá-lo no TDD também sem alterações.

Pashec
fonte
Given-When-Then é o mesmo que MethodName_Scenario_ExpectedBehavior, não é ?!
The Light
1
Não exatamente. Given_When_Then se refere mais a: GivenAnEntity_WhenSomeActionHappens_ThatResultIsExpected O teste deve expressar a vontade de testar um comportamento e não uma implementação .
usar o seguinte comando
1
"Given When Then" é frequentemente referido como pepino. É uma DSL que saiu das ferramentas Pepino, JBehave e Behat.
30816 bytedev
+1 é o melhor método imo. A dissociação de como um método faz algo do que você espera que o resultado seja muito poderoso e evita muitos problemas descritos em outros comentários.
Lee
7

Acho que uma das coisas mais importantes é ser consistente em sua convenção de nomenclatura (e concordo com outros membros de sua equipe). Muitas vezes vejo muitas convenções diferentes usadas no mesmo projeto.

bytedev
fonte
7

Recentemente, criei a seguinte convenção para nomear meus testes, suas classes e conter projetos, a fim de maximizar seus descritores:

Digamos que estou testando a Settingsclasse em um projeto no MyApp.Serializationespaço para nome.

Primeiro, criarei um projeto de teste com o MyApp.Serialization.Testsespaço para nome.

Nesse projeto e, é claro, no namespace, criarei uma classe chamada IfSettings(salva como IfSettings.cs ).

Digamos que estou testando o SaveStrings()método. -> Vou nomear o testeCanSaveStrings() .

Quando eu executo este teste, ele mostra o seguinte título:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Eu acho que isso me diz muito bem o que está testando.

Obviamente, é útil que em inglês o substantivo "Tests" seja o mesmo que o verbo "tests".

Não há limite para a sua criatividade ao nomear os testes, para que possamos obter títulos de frases completos para eles.

Geralmente, os nomes dos testes precisam começar com um verbo.

Exemplos incluem:

  • Detecta (por exemplo DetectsInvalidUserInput)
  • Arremessos (por exemplo ThrowsOnNotFound)
  • Will (por exemplo WillCloseTheDatabaseAfterTheTransaction)

etc.

Outra opção é usar "that" em vez de "if".

O último me salva as teclas e descreve mais exatamente o que estou fazendo, já que não sei, que o comportamento testado está presente, mas estou testando, se estiver.

[ Editar ]

Depois de usar a convenção de nomenclatura acima por um pouco mais agora, descobri que o prefixo If pode ser confuso ao trabalhar com interfaces. Acontece que a classe de teste IfSerializer.cs se parece muito com a interface ISerializer.cs na "Guia Arquivos abertos". Isso pode ser muito irritante ao alternar entre os testes, a classe que está sendo testada e sua interface. Como resultado, eu iria agora escolher que mais de Se como um prefixo.

Além disso, agora eu uso - apenas para métodos nas minhas classes de teste, pois não é considerado uma prática recomendada em nenhum outro lugar - o "_" para separar palavras nos nomes dos meus métodos de teste, como em:

[Test] public void detects_invalid_User_Input()

Acho que isso é mais fácil de ler.

[ Fim da edição ]

Espero que isso gere mais algumas idéias, pois considero nomear testes de grande importância, pois isso pode poupar muito tempo que, de outra forma, seria gasto tentando entender o que os testes estão fazendo (por exemplo, depois de retomar um projeto após um hiato prolongado) .

Thorsten Lorenz
fonte
2

No VS + NUnit, costumo criar pastas no meu projeto para agrupar testes funcionais. Em seguida, crio classes de equipamentos de teste de unidade e nomeio-as de acordo com o tipo de funcionalidade que estou testando. Os métodos [Teste] são nomeados ao longo das linhas de Can_add_user_to_domain:

- MyUnitTestProject   
  + FTPServerTests <- Folder
   + UserManagerTests <- Test Fixture Class
     - Can_add_user_to_domain  <- Test methods
     - Can_delete_user_from_domain
     - Can_reset_password
Kev
fonte
2

Devo acrescentar que a manutenção de seus testes no mesmo pacote, mas em um diretório paralelo à origem que está sendo testada, elimina o inchaço do código quando você estiver pronto para implementá-lo sem ter que fazer muitos padrões de exclusão.

Eu pessoalmente gosto das melhores práticas descritas no "JUnit Pocket Guide" ... é difícil vencer um livro escrito pelo co-autor da JUnit!

Steve Moyer
fonte
3
Não acredite que isso realmente responda à pergunta em questão - você poderia fazer uma edição e referência ao JUnit Pocket Guide? Obrigado!
Nate-Wilkins
0

o nome do caso de teste da classe Foo deve ser FooTestCase ou algo parecido (FooIntegrationTestCase ou FooAcceptanceTestCase) - já que é um caso de teste. consulte http://xunitpatterns.com/ para obter algumas convenções de nomenclatura padrão, como teste, caso de teste, dispositivo de teste, método de teste etc.


fonte