Estou fazendo esta pergunta sobre problemas que experimentei durante projetos de TDD. Percebi os seguintes desafios ao criar testes de unidade.
- Gerando e mantendo dados simulados
É difícil e irrealista manter grandes dados simulados. É ainda mais difícil quando a estrutura do banco de dados sofre alterações.
- Testando a GUI
Mesmo com o MVVM e a capacidade de testar a GUI, é preciso muito código para reproduzir o cenário da GUI.
- Testando o negócio
Tenho experiência que o TDD funciona bem se você o limitar à lógica de negócios simples. No entanto, é difícil testar uma lógica de negócios complexa, pois o número de combinações de testes (espaço de teste) é muito grande.
- Contradição nos requisitos
Na realidade, é difícil capturar todos os requisitos sob análise e design. Muitas vezes, os requisitos de uma nota levam à contradição porque o projeto é complexo. A contradição é encontrada tarde na fase de implementação. O TDD exige que os requisitos sejam 100% corretos. Nesses casos, pode-se esperar que requisitos conflitantes sejam capturados durante a criação de testes. Mas o problema é que esse não é o caso em cenários complexos.
Eu li esta pergunta: Por que o TDD funciona?
O TDD realmente funciona para projetos empresariais complexos ou é praticamente um limite para o tipo de projeto?
Respostas:
Falso.
O teste de unidade não requer dados simulados "grandes". Requer dados simulados suficientes para testar os cenários e nada mais.
Além disso, os programadores verdadeiramente preguiçosos pedem aos especialistas no assunto que criem planilhas simples dos vários casos de teste. Apenas uma planilha simples.
Em seguida, o programador preguiçoso escreve um script simples para transformar as linhas da planilha em casos de teste de unidade. É bem simples, realmente.
Quando o produto evolui, as planilhas dos casos de teste são atualizadas e novos testes de unidade gerados. Faça isso o tempo todo. Realmente funciona.
O que? "Reproduzir"?
O objetivo do TDD é projetar coisas para a testabilidade (desenvolvimento do test drive). Se a GUI é tão complexa, ela precisa ser reprojetada para ser mais simples e testável. Mais simples também significa mais rápido, mais sustentável e mais flexível. Mas, na maioria das vezes, mais simples significa mais testável.
Isso pode ser verdade.
No entanto, pedir aos especialistas no assunto que forneçam os casos de teste principais de uma forma simples (como uma planilha) realmente ajuda.
As planilhas podem se tornar bastante grandes. Mas tudo bem, já que usei um script Python simples para transformar as planilhas em casos de teste.
E. Eu tive que escrever alguns casos de teste manualmente porque as planilhas estavam incompletas.
Contudo. Quando os usuários relataram "bugs", simplesmente perguntei qual caso de teste na planilha estava errado.
Naquele momento, os especialistas no assunto corrigiam a planilha ou adicionavam exemplos para explicar o que deveria acontecer. Os relatórios de erros podem - em muitos casos - ser claramente definidos como um problema de caso de teste. De fato, pela minha experiência, definir o bug como um caso de teste quebrado torna a discussão muito, muito mais simples.
Em vez de ouvir os especialistas tentando explicar um processo de negócios super complexo, eles precisam produzir exemplos concretos do processo.
Não usar o TDD exige absolutamente que os requisitos sejam 100% corretos. Alguns afirmam que o TDD pode tolerar requisitos incompletos e variáveis, onde uma abordagem não-TDD não pode funcionar com requisitos incompletos.
Se você não usar TDD, a contradição será encontrada tarde na fase de implementação.
Se você usa TDD, a contradição é encontrada anteriormente quando o código passa em alguns testes e falha em outros testes. De fato, o TDD fornece uma prova de uma contradição no início do processo, muito antes da implementação (e argumentos durante o teste de aceitação do usuário).
Você tem código que passa em alguns testes e falha em outros. Você olha apenas para esses testes e encontra a contradição. Isso funciona muito, muito bem na prática, porque agora os usuários precisam discutir sobre a contradição e produzir exemplos consistentes e concretos do comportamento desejado.
fonte
sim
Minha primeira exposição ao TDD foi trabalhando nos componentes de middleware para um telefone celular baseado em Linux. Isso acabou resultando em milhões de linhas de código fonte, que por sua vez geravam cerca de 9 gigabytes de código fonte para vários componentes de código aberto.
Todos os autores de componentes deveriam propor uma API e um conjunto de testes de unidade e tê-los revisados pelo projeto por um comitê de pares. Ninguém esperava a perfeição nos testes, mas todas as funções expostas ao público tinham que ter pelo menos um teste e, uma vez que um componente era submetido ao controle de origem, todos os testes de unidade sempre passavam (mesmo se o fizessem porque o componente estava relatando falsamente). funcionou bem).
Sem dúvida, devido ao menos em parte ao TDD e à insistência em que todos os testes de unidade sempre sejam aprovados, a versão 1.0 chegou cedo, dentro do orçamento e com uma estabilidade surpreendente.
Após o lançamento da versão 1.0, porque as empresas queriam poder mudar rapidamente o escopo devido às demandas dos clientes, elas nos disseram para parar de fazer TDD e removeram a exigência de que os testes de unidade passassem. Era espantoso a rapidez com que a qualidade caía no vaso sanitário, e então o cronograma a seguia.
fonte
removed the requirement that unit tests pass. It was astonishing how quickly quality went down the toilet, and then the schedule followed it.
- é como dizer ao seu piloto de F1 que ele não tem permissão para parar nos boxes porque leva muito tempo ... Idiota.Eu diria que quanto mais complexo o projeto, mais benefícios você obtém do TDD. Os principais benefícios são os efeitos colaterais de como o TDD forçará você a escrever o código em pedaços muito menores e muito mais independentes. Os principais benefícios são:
a) Você obtém uma validação muito, muito mais cedo do seu design, porque seu ciclo de feedback é muito mais restrito devido a testes desde o início.
b) Você pode alterar partes e ver como o sistema reage porque você construiu uma colcha de cobertura de teste o tempo todo.
c) O código finalizado será muito melhor como resultado.
fonte
O TDD realmente funciona para projetos complexos?
Sim. Nem todos os projetos, segundo me disseram, funcionam bem com o TDD, mas a maioria dos aplicativos de negócios é boa, e aposto que aqueles que não funcionam bem quando são escritos de maneira TDD pura podem ser escritos de maneira ATDD sem grandes problemas.
Gerando e mantendo dados simulados
Mantenha-o pequeno e tenha apenas o que você precisa, e esse não é o problema assustador que parece. Não me interpretem mal, é uma dor. Mas vale a pena.
Testando a GUI
Teste o MVVM e verifique se ele pode ser testado sem a visualização. Achei isso não mais difícil do que testar qualquer outra parte da lógica de negócios. Testando a visualização no código que não faço, tudo o que você está testando, no entanto, neste momento é a lógica de ligação, que se espera que seja capturada rapidamente quando você faz um teste manual rápido.
Testando o negócio
Não foi um problema. Muitos testes pequenos. Como eu disse acima, alguns casos (o solucionador de quebra-cabeças do Sudoku parece popular) são aparentemente difíceis de executar TDD.
O TDD exige que os requisitos sejam 100% corretos
Não, não. De onde você tirou essa idéia? Todas as práticas ágeis aceitam que os requisitos sejam alterados. Você precisa saber o que está fazendo antes de fazê-lo, mas isso não é o mesmo que exigir que os requisitos sejam 100%. O TDD é uma prática comum no Scrum, onde os requisitos (User Stories) são, por definição, não 100% completos.
fonte
Primeiro, acredito que seu problema é mais sobre o teste unitário do que o TDD, pois não vejo nada realmente específico do TDD (teste primeiro + ciclo de refator vermelho-verde-verde) no que você diz.
O que você quer dizer com dados simulados? Uma simulação deve conter praticamente nenhum dado, ou seja, nenhum campo além daquele ou dois necessários no teste e nenhuma dependência além do sistema em teste. Configurar uma expectativa simulada ou um valor de retorno pode ser feito em uma linha, para que nada de terrível.
Se você quer dizer que o banco de dados sofre alterações sem que as modificações apropriadas tenham sido feitas no modelo de objeto, os testes de unidade de poço estão aqui para avisá-lo disso. Caso contrário, as alterações no modelo devem ser refletidas nos testes de unidade, obviamente, mas com as indicações de compilação é uma coisa fácil de fazer.
Você está certo, o teste de unidade da GUI (exibição) não é fácil e muitas pessoas estão indo bem sem ela (além disso, testar a GUI não faz parte do TDD). Por outro lado, o teste de unidade do seu Controller / Presenter / ViewModel / qualquer camada intermediária é altamente recomendado, na verdade, é uma das principais razões pelas quais padrões como MVC ou MVVM são.
Se sua lógica de negócios é complexa, é normal que seus testes de unidade sejam difíceis de projetar. Cabe a você torná-los o mais atômico possível, cada um testando apenas uma responsabilidade do objeto sob teste. Os testes de unidade são ainda mais necessários em um ambiente complexo, porque fornecem uma rede de segurança que garante que você não infringe as regras ou requisitos de negócios à medida que faz alterações no código.
Absolutamente não. O software bem-sucedido exige que os requisitos estejam 100% corretos;) Os testes de unidade refletem apenas qual é a sua visão dos requisitos atualmente; se a visão for falha, seu código e seu software também serão, testes de unidade ou não ... E é aí que os testes de unidade brilham: com títulos de teste suficientemente explícitos, suas decisões de projeto e interpretação de requisitos se tornam transparentes, o que facilita apontar seu dedo sobre o que precisa ser alterado na próxima vez em que o cliente disser "essa regra de negócios não é exatamente como eu gostaria".
fonte
Eu tenho que rir quando ouço alguém reclamar que o motivo pelo qual eles não podem usar o TDD para testar sua aplicação é porque ela é muito complicada. Qual é a alternativa? Tem macacos de teste batendo em hectares de teclados? Deixe os usuários serem os testadores? O quê mais? Claro que é difícil e complexo. Você acha que a Intel não testa seus chips até que eles sejam enviados? Como é "cabeça na areia"?
fonte
Eu descobri que o TDD (e o teste de unidade em geral) é praticamente impossível por um motivo relacionado: algoritmos complexos, novos e / ou difusos. O problema que eu mais encontro nos protótipos de pesquisa que escrevo é que não tenho idéia de qual é a resposta certa senão executando meu código. É muito complicado descobrir com razoabilidade à mão qualquer coisa que não seja casos ridiculamente triviais. Isso é especialmente verdadeiro se o algoritmo envolver heurísticas, aproximações ou não determinismos. Eu ainda tento testar a funcionalidade de nível inferior da qual esse código depende e o uso afirma fortemente como verificações de integridade. Meu método de teste de último recurso é escrever duas implementações diferentes, idealmente em duas linguagens diferentes, usando dois conjuntos diferentes de bibliotecas e comparar os resultados.
fonte
Da minha experiência: Sim para Unittests (teste de módulos / recursos isoladamente), porque esses problemas geralmente não têm os problemas mencionados: (Gui, Mvvm, Business-Modell). Eu nunca tive mais do que três zombarias / stubs para preencher uma unittest (mas talvez seu domínio exija mais).
No entanto, não tenho certeza se o TDD poderia resolver os problemas mencionados na integração ou no teste de ponta a ponta com testes no estilo BDD.
Mas pelo menos alguns problemas podem ser reduzidos .
Isso é verdade se você deseja fazer uma cobertura completa no nível de teste de integração ou teste de ponta a ponta. Pode ser mais fácil fazer a cobertura completa em um nível mais unitário.
Exemplo: Verificando Permissões de Usuário Complexas
Testar a função
IsAllowedToEditCusterData()
em um nível de teste de integração exigiria solicitar diferentes objetos para obter informações sobre usuário, domínio, cliente, ambiente .....Zombar dessas peças é bastante difícil. Isto é especialmente verdade se
IsAllowedToEditCusterData()
for necessário conhecer esses diferentes objetos.Em um nível Unittest, você teria uma função
IsAllowedToEditCusterData()
que utiliza, por exemplo, 20 parâmetros que contêm tudo o que a função precisa saber. ComoIsAllowedToEditCusterData()
não é necessário saber quais campos auser
, adomain
, acustomer
, .... possui isso é fácil de testar.Quando eu tive que implementar,
IsAllowedToEditCusterData()
eu tinha duas sobrecargas:Uma sobrecarga que nada mais faz do que obter esses 20 parâmetros e depois chamar a sobrecarga com os 20 parâmetros que tomam a decisão.
(meu
IsAllowedToEditCusterData()
tinha apenas 5 parâmetros e eu precisava de 32 combinações diferentes para testá-lo completamente)Exemplo
fonte
A resposta triste é que nada realmente funciona para grandes projetos complexos!
O TDD é tão bom quanto qualquer outra coisa e melhor que a maioria, mas o TDD por si só não garante o sucesso em um projeto grande. No entanto, aumentará suas chances de sucesso. Especialmente quando usado em combinação com outras disciplinas de gerenciamento de projetos (verificação de requisitos, casos de uso, matriz de rastreabilidade de requisitos, orientações de código etc. etc.).
fonte
Lembre-se de que os testes de unidade são especificações impostas . Isso é especialmente valioso em projetos complexos. Se a sua antiga base de código não tiver nenhum teste para fazer backup, ninguém se atreverá a mudar nada, porque eles terão medo de quebrar alguma coisa.
"Wtf. Por que esse ramo de código está lá? Não sei, talvez alguém precise, é melhor deixá-lo lá do que incomodar alguém ..." Com o tempo, os projetos complexos se tornam um lixo.
Com os testes, qualquer pessoa pode dizer com segurança "Fiz mudanças drásticas, mas todos os testes ainda estão passando". Por definição, ele não quebrou nada. Isso leva a projetos mais ágeis que podem evoluir. Talvez uma das razões pelas quais ainda precisamos de pessoas para manter COBOL seja porque os testes não eram populares desde então: P
fonte
Eu vi um projeto grande e complexo falhar completamente quando o TDD foi usado exclusivamente, ou seja, sem pelo menos configurar um depurador / IDE. Os dados e / ou testes simulados mostraram-se insuficientes. Os dados reais dos clientes Beta eram confidenciais e não puderam ser copiados ou registrados. Portanto, a equipe de desenvolvedores nunca conseguiu consertar os bugs fatais que se manifestavam quando apontados para dados reais, e todo o projeto foi descartado, todos foram demitidos.
A maneira de corrigir esse problema seria acioná-lo em um depurador no site do cliente, viver com dados reais, percorrer o código, com pontos de interrupção, observar variáveis, observar a memória etc. No entanto, essa equipe, que pensavam que seu código era adequado para adornar as melhores torres de marfim, durante um período de quase um ano nunca haviam acionado seu aplicativo. Isso me surpreendeu.
Então, como tudo, o equilíbrio é a chave. TDD pode ser bom, mas não confie nele exclusivamente.
fonte
Eu acho que sim, veja Test Driven Development realmente funciona
fonte
Se a combinação de orçamento, requisitos e habilidades da equipe estiver no quadrante do espaço do projeto, "abandone a esperança de todos os que entram aqui", então, por definição, é extremamente provável que o projeto falhe.
Talvez os requisitos sejam complexos e voláteis, a infraestrutura instável, a equipe mais jovem e com alta rotatividade, ou o arquiteto seja um idiota.
Em um projeto TDD, o sintoma dessa falha iminente é que os testes não podem ser gravados dentro do cronograma; você tenta, apenas para descobrir 'isso vai levar tanto tempo, e nós só temos isso '.
Outras abordagens mostrarão sintomas diferentes quando falharem; entrega mais comum de um sistema que não funciona. Política e contratos determinarão se isso é preferível.
fonte
TDD
pode parecer uma dor inicial, mas a longo prazo seria seu melhor amigo, acredite em mimTDD
realmente tornará o aplicativo sustentável e seguro a longo prazo.fonte