TDD: Estou fazendo certo?

14

Sou um novo programador (há apenas um ano que aprendo) e, no meu objetivo de melhorar, recentemente aprendi sobre o TDD. Eu queria ter o hábito de usá-lo, pois parece muito útil. Eu queria verificar e ter certeza de que estou usando corretamente.

O que estou fazendo:

  1. Pense em um novo método que eu preciso.
  2. Crie um teste para esse método.
  3. Teste de falha.
  4. Método de gravação.
  5. Teste de aprovação.
  6. Método de refatoração.
  7. Repetir.

Eu estou fazendo isso para CADA método que eu escrevo, há algum que eu não deveria me preocupar? Mais tarde, costumo pensar em uma maneira de testar meus métodos já existentes de uma maneira ou situação diferente. Devo fazer esses novos testes, ou já que cada método já tem um teste próprio, eu não deveria me incomodar? Posso ser mais de testar o meu código, eu acho que é a minha principal preocupação em pedir isso.

EDITAR

Além disso, isso era algo que eu estava pensando. Ao fazer algo como fazer uma GUI, o TDD seria necessário nessa situação? Pessoalmente, não consigo pensar em como escreveria testes para isso.

    
por cgasser 18.05.2012 / 19:52
fonte

9 respostas

16

O que você está descrevendo como um fluxo de trabalho não é, na minha opinião, o Espírito de TDD.

A sinopse do livro de Kent Becks na Amazon diz:

Quite simply, test-driven development is meant to eliminate fear in application development. While some fear is healthy (often viewed as a conscience that tells programmers to "be careful!"), the author believes that byproducts of fear include tentative, grumpy, and uncommunicative programmers who are unable to absorb constructive criticism. When programming teams buy into TDD, they immediately see positive results. They eliminate the fear involved in their jobs, and are better equipped to tackle the difficult challenges that face them. TDD eliminates tentative traits, it teaches programmers to communicate, and it encourages team members to seek out criticism However, even the author admits that grumpiness must be worked out individually! In short, the premise behind TDD is that code should be continually tested and refactored.

TDD prática

Testes automatizados formais, especialmente o Teste Unitário, em todos os métodos de todas as classes, é tão ruim quanto um antipadrão e não testa nada. Há um equilíbrio a ser obtido. Você está escrevendo testes de unidade para cada método setXXX/getXXX , eles também são métodos!

Além disso, os testes podem ajudar a economizar tempo e dinheiro, mas não se esqueça de que eles custam tempo e dinheiro para desenvolver e são códigos, por isso eles custam tempo e dinheiro para manter. Se eles se atrofiam por falta de manutenção, então eles se tornam um passivo mais do que um benefício.

Como tudo assim, há um equilíbrio que não pode ser definido por ninguém além de você mesmo. Qualquer dogma de qualquer maneira é provavelmente mais errado do que correto.

Uma boa métrica é um código que é crítico para a lógica de negócios e está sujeito a modificações frequentes com base na mudança de requisitos. Essas coisas precisam de testes formais automatizados, o que seria um grande retorno do investimento.

Você vai ser muito pressionado para encontrar muitas lojas profissionais que funcionam assim também. Simplesmente não faz sentido gastar dinheiro testando coisas que, para todos os fins práticos, nunca mudam depois de um simples teste de fumaça ser realizado. Escrever testes de unidade automatizados formais para métodos .getXXX/.setXXX é um excelente exemplo disso, uma completa perda de tempo.

It is now two decades since it was pointed out that program testing may convincingly demonstrate the presence of bugs, but can never demonstrate their absence. After quoting this well-publicized remark devoutly, the software engineer returns to the order of the day and continues to refine his testing strategies, just like the alchemist of yore, who continued to refine his chrysocosmic purifications.

-- Edsger W. Djikstra. (Written in 1988, so it's now closer to 4.5 decades.)

Veja também esta resposta .

    
por 18.05.2012 / 20:18
fonte
13

Você está muito perto. Tente pensar dessa maneira um pouco diferente.

  1. Pense em um novo comportamento de que preciso.
  2. Crie um teste para esse comportamento.
  3. Teste de falha.
  4. Escreva novo ou amplie o método existente.
  5. Teste de aprovação.
  6. Refatorar código.
  7. Repetir.

Não crie automaticamente getters e setters para todas as propriedades . Não pense em um método completo e escreva o teste ( s) para cobrir todas as funcionalidades . Tente encapsular as propriedades dentro da classe e escreva métodos para fornecer o comportamento que você precisa. Deixe seus métodos evoluírem para um bom design, em vez de tentar planejá-los antecipadamente. Lembre-se de que o TDD é um processo de design, não um processo de teste. A vantagem que ele tem sobre outros processos de design é deixar um fluxo de testes de regressão automatizada para trás, em vez de um pedaço de papel que você joga na lixeira.

Além disso, lembre-se de as três regras de TDD do tio Bob .

  1. Você não tem permissão para escrever nenhum código de produção, a menos que seja para fazer uma passagem de teste de unidade com falha.
  2. Você não tem permissão para escrever mais de um teste de unidade do que é suficiente para falhar; e falhas de compilação são falhas.
  3. Você não tem permissão para escrever mais código de produção do que o suficiente para passar no único teste de unidade com falha.
por 18.05.2012 / 20:28
fonte
5

Poucas coisas para adicionar às respostas dos outros:

  1. Existe algo como over testing. Você quer ter certeza de que seus testes de unidade se sobrepõem o mínimo possível. Não faz sentido ter vários testes verificando as mesmas condições no mesmo trecho de código. Por outro lado, quando você refatora seu código de produção e você tem muitos testes que se sobrepõem a essa seção, você terá que voltar e consertar todos esses testes. Considerando que, se eles não se sobrepõem, então uma mudança irá no máximo quebrar apenas um teste.

  2. Só porque você pensou em uma maneira melhor de escrever um teste, eu não voltaria lá e começaria a reescrevê-lo. Isso está voltando para os indivíduos que continuam escrevendo e reescrevendo a mesma classe / função porque tentam torná-la perfeita. Nunca será perfeito, então siga em frente. Quando você descobrir um método melhor, mantenha-o no fundo da mente (ou adicione aos comentários do teste). Da próxima vez que você estiver lá, e perceber o benefício imediato de mudar para o novo caminho, é hora de refatorar. Caso contrário, se o recurso estiver pronto e você for embora e tudo funcionar, deixe-o funcionando.

  3. O TDD se concentra em fornecer valor imediato, não simplesmente certificando-se de que todas as funções são testáveis. Quando você adiciona funcionalidade, comece perguntando "o que o cliente precisa". Em seguida, defina uma interface para fornecer ao cliente o que ele precisa. Em seguida, implemente o que for necessário para fazer o teste passar. O TDD é quase como testar cenários de casos de uso (incluindo todos os "e-ses"), em vez de simplesmente codificar funções públicas e testar cada uma delas.

  4. Você perguntou sobre como testar o código da GUI. Procure padrões de "Humble Dialog" e "MVVM". A ideia por trás disso é que você cria um conjunto de classes "modelo de exibição", que na verdade não tem lógica específica da interface do usuário. No entanto, essas classes terão toda a lógica de negócios que geralmente faz parte da sua interface do usuário e essas classes devem ser 100% testáveis. O que resta é um shell de interface do usuário muito fino e, sim, normalmente esse shell é deixado sem cobertura de teste, mas nesse ponto ele não deve ter quase nenhuma lógica.

  5. Se você tem uma grande parte do código existente, como poucos sugeriram, você não deve começar a adicionar testes de unidade em qualquer lugar. Ele levará você para sempre e você não terá o benefício de adicionar testes de unidade a 80% das classes que são estáveis e não serão alteradas no futuro próximo (ou não tão próximo). No entanto, para novos trabalhos, acho que usar o desenvolvimento de TDD com código ALL é extremamente benéfico. Não apenas você acaba com um conjunto de testes automatizados quando você termina, mas o desenvolvimento real tem enormes benefícios:

    • Ao considerar testabilidade, você escreverá um código menos acoplado e mais modular
    • Ao considerar seu contrato público antes de mais nada, você acabará com interfaces públicas que são muito mais limpas
    • Conforme você escreve o código, a verificação da nova funcionalidade leva milissegundos em comparação com a execução de todo o aplicativo e a tentativa de forçar a execução no caminho certo. Minha equipe ainda libera um código de tratamento de erros que ainda não foi executado UMA VEZ, porque eles não conseguiram obter o conjunto correto de condições para acontecer. É incrível quanto tempo perdemos quando, mais tarde, no controle de qualidade, essas condições acontecem. E sim, muito deste código é o que alguém teria considerado "não área para muita mudança no futuro, uma vez que o teste de fumaça é feito".
por 18.05.2012 / 22:43
fonte
1

Existem alguns métodos que não estão sendo testados, ou seja, esses testes. No entanto, há algo a ser dito para alguns testes serem adicionados após o código inicial ter sido escrito, como condições de contorno e outros valores, para que possa haver vários testes em um único método.

Enquanto você pode testar o seu código, geralmente vem onde alguém quer testar todas as possíveis permutações de entradas que não soam como o que você está fazendo. Por exemplo, se você tem um método que aceita um caractere, você escreve um teste para todos os valores possíveis que podem ser inseridos? Isso seria onde você poderia fazer um overtesting, IMO.

    
por 18.05.2012 / 19:59
fonte
1

Geralmente você está fazendo certo.

Testes são códigos. Então, se você puder melhorar o teste, vá em frente e refatore-o. Se você acha que um teste pode ser melhorado, vá em frente e altere-o. Não tenha medo de substituir um teste por um melhor.

Eu recomendo testar seu código, evitando especificar como o código deve fazer o que está fazendo. Os testes devem analisar os resultados dos métodos. Isso ajudará na refatoração. Alguns métodos não precisam ser testados explicitamente (por exemplo, getters e setters simples) porque você os usará para verificar os resultados de outros testes.

    
por 18.05.2012 / 20:06
fonte
0

Minha opinião sobre o TDD é que o ferramental criou um mundo de desenvolvedores de estilo 'aponte e clique'. Só porque as ferramentas criam um stub de teste para cada método não significa que você deveria estar escrevendo testes para cada método. Algumas pessoas estão 'renomeando' o TDD como BDD (behavior driven development), onde os testes são muito maiores e se destinam a testar o comportamento da classe, e não cada pequeno método complicado.

Se você projetar seus testes para testar a classe como ela pretende ser usada, você começa a ganhar alguns benefícios, especialmente quando começa a escrever testes que se exercitam um pouco mais que cada método, especialmente quando você começa a testar interação desses métodos. Eu suponho que você poderia pensar nisso como escrever testes para uma classe, ao invés de métodos. Em qualquer caso, você ainda deve escrever 'testes de aceitação' que exercitem a combinação de métodos para garantir que não haja contradições ou conflitos em como eles são usados juntos.

Não confunda TDD com testes - não é. O TDD é projetado para que você escreva código para exercitar seus requisitos e não para testar os métodos. É um ponto sutil, mas importante, que muitas vezes é perdido em pessoas que escrevem cegamente código de teste para cada método. É que você deveria estar escrevendo testes que garantam que seu código faça o que você quer, não que o código que você escreveu funcione como deveria.

Há alguns bons links à direita sobre o BDD v TDD. Confira-os.

    
por 18.05.2012 / 20:16
fonte
0

Quando você começa aprendendo TDD, sim, você deve seguir cegamente a abordagem dogmática de não escrever uma única linha de código, exceto para fazer um teste falhar e escrever apenas o suficiente de um teste para falhar (e falhar pelo motivo certo / esperado).

Depois de aprender sobre o que é o TDD, você pode decidir que certos tipos de coisas não valem a pena ser testados. Esta é a mesma abordagem que você deve seguir para tudo, e as artes marciais japonesas chamam isso de " shuhari ". (O link também explica como alguém pode progredir através dos estágios de aprendizado sem um professor, que é, eu suspeito, como a maioria das pessoas tem que aprender.)

    
por 22.05.2012 / 12:02
fonte
0

Eu acredito que você está fazendo overtesting.

Eu pratico TDD há muitos anos e, na minha experiência, quando o TDD é realizado de forma eficaz, você obtém dois benefícios principais:

  • Fornecer feedback rápido
  • Ativar refatoração

Fornecer feedback rápido

Particularmente com linguagens dinâmicas, posso executar os testes relevantes em menos de um segundo. E eu tenho observadores do sistema de arquivos executando esses testes automaticamente quando um arquivo de origem é alterado no disco. Assim, praticamente não tenho tempo de espera para testes, e imediatamente sei se o código que escrevo foi o esperado. Assim, o TDD leva a uma maneira muito eficiente de trabalhar.

Ativar refatoração

Se você tiver uma boa suíte de testes, poderá refatorar com segurança, à medida que obtiver novos insights sobre como o sistema deve ser projetado.

Uma boa suíte de testes permite que você mova a responsabilidade em seu código e ainda tenha certeza de que o código funciona como esperado após a mudança. E você deve conseguir fazer isso com pequenas alterações no código de teste.

Se você escrever testes para cada método em seu sistema, então é provável que você não possa refatorar seu código facilmente, cada refatorador de seu código exigirá mudanças maciças no código de teste. E você pode ter certeza de que o código de teste ainda funciona como esperado? Ou você acidentalmente introduziu um bug no código de teste, o que consequentemente leva a um erro no código de produção?

Se você, no entanto, como também sugerido na resposta do pdr , focar no comportamento em vez de métodos ao escrever testes, você terá testes que exigirão muito menos alterações ao refatorar o sistema.

Ou como Ian Cooper disse nesta apresentação (eu citei da memória, então pode não ser citado corretamente):

Your reason for writing a new test should be adding a new behavior, not adding a new class

    
por 25.07.2017 / 08:39
fonte
-2

Você deve testar todos os métodos públicos .

A pegadinha aqui é que, se seus métodos públicos são muito pequenos, você provavelmente está expondo muita informação. A prática comum de expor todas as propriedades como getXXX() realmente interrompe o encapsulamento.

Se seus métodos públicos forem realmente o comportamento da classe, você deverá testá-los. Se não, eles não são bons métodos públicos.

EDITAR: a resposta do pdr é muito mais completa do que a minha.

    
por 18.05.2012 / 22:20
fonte

Tags