Pergunta

Como desenvolvedor iniciante que está entrando no ritmo do meu primeiro projeto profissional, procuro desenvolver bons hábitos o mais rápido possível.No entanto, descobri que muitas vezes me esqueço de testar, adiar ou fazer vários testes no final de uma compilação, em vez de um de cada vez.

Minha pergunta é qual ritmo você gosta de entrar ao trabalhar em grandes projetos e onde os testes se encaixam nisso.

Foi útil?

Solução

Bem, se você quiser seguir os caras do TDD, antes de começar a codificar ;)

Estou na mesma posição que você.Quero me aprofundar mais nos testes, mas atualmente estou em uma posição em que estamos trabalhando para "retirar o código" em vez de "colocar o código corretamente", o que me assusta profundamente.Então, estou lentamente tentando integrar processos de teste em meu ciclo de desenvolvimento.

Atualmente, Eu testo enquanto codifico, tentando decifrar o código enquanto o escrevo.Eu acho difícil entrar na mentalidade do TDD.Está demorando, mas é assim que eu faria querer trabalhar..

EDITAR:

Achei que provavelmente deveria expandir isso, este é o meu "processo de trabalho" básico...

  1. Planeje o que eu quero do código, possível design de objetos, qualquer que seja.
  2. Crie minha primeira aula, adicione um grande comentário ao top que é o que é minha "visão" para a classe.
  3. Descreva os cenários básicos de teste.Estes se tornarão basicamente os testes de unidade.
  4. Crie meu primeiro método.Também escrevendo um breve comentário explicando como é esperado trabalhar.
  5. Escreva um teste automatizado para ver se ele faz o que espero.
  6. Repita as etapas 4 a 6 para cada método (observe que os testes automatizados estão em uma lista enorme executada em F5).
  7. Em seguida, crio alguns testes robustos para emular a classe no ambiente de trabalho, obviamente corrigindo quaisquer problemas.
  8. Se algum novo bug surgir depois disso, volto e escrevo o novo teste, certifico-me de que ele falhe (isso também serve como prova de conceito para o bug) e depois o corrijo.

Espero que ajude..Aberto a comentários sobre como melhorar isso, como eu disse é uma preocupação minha.

Outras dicas

Antes de fazer check-in do código.

Primeiro e frequentemente.Se estou criando alguma nova funcionalidade para o sistema, procurarei definir inicialmente as interfaces e depois escrever testes de unidade para essas interfaces.Para decidir quais testes escrever, considere a API da interface e a funcionalidade que ela fornece, pegue uma caneta e papel e pense um pouco sobre possíveis condições de erro ou maneiras de provar que está fazendo o trabalho correto.Se isso for muito difícil, é provável que sua API não seja boa o suficiente.Em relação aos testes, veja se você consegue evitar escrever testes de "integração" que testam mais de um objeto específico e mantê-los como testes "unitários".

Em seguida, crie uma implementação padrão da sua interface (que não faça nada, retorne valores inúteis, mas não gere exceções), conecte-a aos testes para garantir que os testes falhem (isso testa se seus testes funcionam!:)).Em seguida, escreva a funcionalidade e execute novamente os testes.Esse mecanismo não é perfeito, mas cobrirá muitos erros simples de codificação e fornecerá a oportunidade de executar seu novo recurso sem precisar conectá-lo ao aplicativo inteiro.

Depois disso, você precisará testá-lo no aplicativo principal com a combinação dos recursos existentes.É aqui que o teste é mais difícil e, se possível, deve ser parcialmente terceirizado para um bom testador de controle de qualidade, pois ele terá o talento de quebrar coisas.Embora ajude se você também tiver essas habilidades.Fazer os testes corretamente é um talento que você precisa aprender para ser honesto.Minha própria experiência vem de minhas próprias implantações ingênuas e dos bugs subsequentes que foram relatados pelos usuários quando eles o usaram com raiva.

No início, quando isso aconteceu comigo, achei irritante que o usuário estivesse tentando quebrar meu software intencionalmente e quis marcar todos os "bugs" como "problemas de treinamento".No entanto, depois de refletir sobre isso, percebi que é nosso papel (como desenvolvedores) tornar o aplicativo o mais simples e confiável possível para uso, mesmo por idiotas.É nosso papel capacitar os idiotas e é por isso que recebemos o dólar.Tratamento idiota.

Para testar assim com eficácia, você precisa ter a mentalidade de tentar quebrar tudo.Assuma o manto de um usuário que aperta os botões e geralmente tenta destruir seu aplicativo de maneiras estranhas e maravilhosas.Suponha que, se você não encontrar falhas, elas serão descobertas na produção, causando séria perda de prestígio para sua empresa.Assuma total responsabilidade por todos esses problemas e amaldiçoe-se quando um bug pelo qual você é responsável (ou mesmo parcialmente responsável) for descoberto na produção.

Se você fizer a maior parte do que foi dito acima, deverá começar a produzir um código muito mais robusto; no entanto, é uma forma de arte e requer muita experiência para ser bom.

Uma boa chave para lembrar é

"Teste cedo, teste frequentemente e teste novamente, quando achar que terminou"

Quando testar?Quando é importante que o código funcione corretamente!

Ao hackear algo para mim, eu testo no final.Má prática, mas geralmente são coisas pequenas que usarei algumas vezes e pronto.

Em um projeto maior, escrevo testes antes de escrever uma classe e executo os testes após cada alteração nessa classe.

Eu testo constantemente.Depois de terminar um loop dentro de uma função, executo o programa e atingo um ponto de interrupção no topo do loop e, em seguida, executo-o.Isso tudo é apenas para ter certeza de que o processo está fazendo exatamente o que eu quero.

Então, quando uma função for concluída, você a testa por completo.Você provavelmente deseja definir um ponto de interrupção logo antes da função ser chamada e verificar seu depurador para ter certeza de que funciona perfeitamente.

Acho que diria:"Teste frequentemente."

Recentemente adicionei testes unitários ao meu fluxo de trabalho regular, mas escrevo testes unitários:

  • para expressar os requisitos para cada novo módulo de código (logo depois de escrever a interface, mas antes de escrever a implementação)
  • toda vez que penso "era melhor...quando eu terminar"
  • quando algo quebra, para quantificar o bug e provar que o corrigi
  • quando escrevo código que aloca ou desaloca memória explicitamente --- detesto procurar vazamentos de memória ...

Eu executo os testes na maioria das compilações e sempre antes de executar o código.

Comece com testes de unidade.Especificamente, verifique TDD, Test Driven Development.O conceito por trás do TDD é escrever primeiro os testes de unidade e depois escrever seu código.Se o teste falhar, você volta e trabalha novamente em seu código.Se passar, você passa para o próximo.

Eu adoto uma abordagem híbrida para TDD.Não gosto de escrever testes contra nada, então geralmente escrevo parte do código primeiro e depois coloco os testes de unidade.É um processo iterativo, com o qual você nunca termina.Você altera o código e executa seus testes.Se houver alguma falha, corrija e repita.

O outro tipo de teste é o teste de integração, que surge posteriormente no processo e normalmente pode ser feito por uma equipe de teste de controle de qualidade.De qualquer forma, os testes de integração atendem à necessidade de testar as peças como um todo.É o produto funcional que você está preocupado em testar.Este é mais difícil de lidar porque geralmente envolve ferramentas de teste automatizadas (como Robot, por exemplo).

Além disso, dê uma olhada em um produto como o CruiseControl.NET para fazer compilações contínuas.CC.NET é bom porque ele executará seus testes de unidade com cada compilação, notificando você imediatamente sobre quaisquer falhas.

Não fazemos TDD aqui (embora alguns o defendam), mas nossa regra é que você deve verificar seus testes unitários com suas alterações.Isso nem sempre acontece, mas é fácil voltar e analisar um conjunto de alterações específico e ver se os testes foram escritos ou não.

Acho que se eu esperar até o final de escrever algum novo recurso para testar, esqueço muitos dos casos extremos que pensei que poderiam quebrar o recurso.Tudo bem se você estiver fazendo coisas para aprender por si mesmo, mas em um ambiente profissional, considero meu fluxo a forma clássica de:Vermelho, Verde, Refatorar.

Vermelho:Escreva seu teste para que ele falhe.Dessa forma, você sabe que o teste está afirmando a variável correta.

Verde:Faça seu novo teste passar da maneira mais fácil possível.Se isso significa codificá-lo, tudo bem.Isso é ótimo para aqueles que querem apenas que algo funcione imediatamente.

Refatorar:Agora que seu teste foi aprovado, você pode voltar e alterar seu código com confiança.Sua nova mudança quebrou seu teste?Ótimo, sua mudança teve uma implicação que você não percebeu, agora seu teste está lhe dizendo.

Esse ritmo me fez acelerar meu desenvolvimento ao longo do tempo porque basicamente tenho um compilador de histórico para todas as coisas que achei que precisavam ser verificadas para que um recurso funcionasse!Isso, por sua vez, leva a muitos outros benefícios, que não abordarei aqui...

Muitas ótimas respostas aqui!

Tento testar no nível mais baixo que faz sentido:

  • Se um único cálculo ou condicional for difícil ou complexo, adicione código de teste enquanto o escreve e certifique-se de que cada parte funcione.Comente o código de teste quando terminar, mas deixe-o lá para documentar como você testou o algoritmo.

  • Teste cada função.

    • Exercite cada ramo pelo menos uma vez.
    • Exercite o condições de contorno -- valores de entrada nos quais o código muda seu comportamento -- para detectar erros "off by one".
    • Teste várias combinações de entradas válidas e inválidas.
    • Procure situações que possam quebrar o código e teste-as.
  • Teste cada módulo com a mesma estratégia acima.

  • Teste o corpo do código como um todo para garantir que os componentes interajam corretamente.Se você foi diligente nos testes de nível inferior, este é essencialmente um "teste de confiança" para garantir que nada quebrou durante a montagem.

Como a maior parte do meu código é para dispositivos embarcados, presto atenção especial à robustez, à interação entre vários threads, tarefas e componentes e ao uso inesperado de recursos:memória, CPU, espaço no sistema de arquivos, etc..

Em geral, quanto mais cedo você encontrar um erro, mais fácil será isolá-lo, identificá-lo e corrigi-lo – e mais tempo você gastará criando, em vez de perseguir o próprio rabo.*

**Eu sei, -1 para a referência gratuita de ponteiro de buffer!*

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