Pergunta

Eu uso atualmente uma convenção simples para meus testes de unidade. Se eu tiver uma classe chamada "EmployeeReader", eu criar uma classe de teste chamado "EmployeeReader.Tests Eu, então, criar todos os testes para a classe na classe de teste com nomes como:.

  • Reading_Valid_Employee_Data_Correctly_Generates_Employee_Object
  • Reading_Missing_Employee_Data_Throws_Invalid_Employee_ID_Exception

e assim por diante.

I foram recentemente ler sobre um diferente tipo de convenção de nomenclatura usado em BDD. I como a legibilidade deste nomeação, para acabar com uma lista de testes algo como:

  • When_Reading_Valid_Employee (fixação)
    • Employee_Object_Is_Generated (método)
    • Employee_Has_Correct_ID (método)
  • When_Reading_Missing_Employee (fixação)
    • An_Invalid_Employee_ID_Exception_Is_Thrown (método)

e assim por diante.

Alguém tem usado ambos os estilos de nomear? Você pode fornecer qualquer conselho, benefícios, inconvenientes, armadilhas, etc. para me ajudar a decidir se a opção ou não para o meu próximo projeto?

Foi útil?

Solução

O segundo exemplo (com um dispositivo elétrico para cada "tarefa" lógico, em vez de um para cada classe) tem a vantagem de que você pode ter diferentes de configuração e lógica TearDown para cada tarefa, simplificando assim os seus métodos de ensaio individuais e torná-los mais legível.

Você não precisa instalar em um ou outro como um padrão. Nós usamos uma mistura de ambos, dependendo de quantos diferentes "tarefas" temos de teste para cada classe.

Outras dicas

A convenção de nomenclatura Eu tenho usado é:

functionName_shouldDoThis_whenThisIsTheSituation

Por exemplo, estes seriam alguns nomes de teste para a função 'pop' de uma pilha

pop_shouldThrowEmptyStackException_whenTheStackIsEmpty

pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack

Eu sinto o segundo é melhor porque torna os testes de unidade mais legível para os outros como longas filas fazer o olhar código mais difícil de ler ou torná-lo mais difícil de percorrer. Se você ainda sente que há qualquer ambiguidade quanto ao que o teste faz, você pode adicionar comentários a esclarecer este assunto.

A parte do raciocínio por trás da segunda convenção de nomenclatura que você faz referência é que você está a criação de testes e especificações comportamentais ao mesmo tempo. Você estabelece o contexto em que as coisas estão acontecendo eo que realmente deve então acontecer dentro desse contexto. (Na minha experiência, as observações / métodos de ensaio muitas vezes começam com "should_", de modo a obter um padrão "When_the_invoicing_system_is_told_to_email_the_client", "should_initiate_connection_to_mail_server formato".)

Existem ferramentas que irão refletir sobre seus dispositivos de teste e de saída de uma folha html especificação bem formatado, extirpando-se os sublinhados. Você acaba com documentação legível que está em sincronia com o código real (desde que você mantenha sua alta cobertura de teste e precisa).

Dependendo da história / recurso / subsistema no qual você está trabalhando, estas especificações podem ser mostrados e compreendida pelas partes interessadas não-programador para a verificação e feedback, que está no coração da ágil e BDD em particular.

Eu uso o segundo método, e isso realmente ajuda a descrever o que o software deve fazer. Eu também uso classes aninhadas para descrever contexto mais detalhada.

Em essência, classes de teste são contextos, que podem ser aninhadas, e métodos são todas as afirmações uma linha. Por exemplo,

public class MyClassSpecification
{
    protected MyClass instance = new MyClass();

    public class When_foobar_is_42 : MyClassSpecification 
    {
        public When_foobar_is_42() {
            this.instance.SetFoobar( 42 ); 
        }

        public class GetAnswer : When_foobar_is_42
        {
            private Int32 result;

            public GetAnswer() {
                this.result = this.GetAnswer();
            }

            public void should_return_42() {
                Assert.AreEqual( 42, result );
            }
        }
    }
}

que vai me dar saída a seguir no meu corredor de teste:

MyClassSpecification+When_foobar_is_42+GetAnswer
    should_return_42

Eu fui para baixo as duas estradas que você descreve na sua pergunta, bem como alguns outros ... Sua primeira alternativa é bastante simples e fácil de entender para a maioria das pessoas. Eu, pessoalmente, gosto do estilo BDD (seu segundo exemplo) mais porque isola diferentes contextos e observações grupos nesses contextos. Th desvantagem única real é que ele gera mais código para começar a fazê-lo se sente um pouco mais complicado até ver os testes puras. Além disso, se você usar a herança para configuração reutilização dispositivo elétrico você quer um TestRunner que gera a cadeia de herança. Considere uma classe "An_empty_stack" e que pretende reutilizá-lo para que, em seguida, fazer uma outra classe: "When_five_is_pushed_on: An_empty_stack" você quer que como saída e não apenas "When_five_is_pushed_on". Se o seu TestRunner não suporta este seus testes irá conter informações redundantes como: "When_five_is_pushed_on_empty_stack: An_empty_stack". Apenas para fazer o bom saída

voto i para chamar a classe caso de teste: EmployeeReaderTestCase e chamando os métodos () como http: // xunitpatterns. com / Organization.html e http://xunitpatterns.com/Organization. html # Teste% 20Naming% 20Conventions

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