Pergunta

O que eu perco ao adotar o design orientado a testes?

Liste apenas pontos negativos;não liste os benefícios escritos de forma negativa.

Foi útil?

Solução

Várias desvantagens (e não estou afirmando que não haja benefícios - especialmente ao escrever a base de um projeto - economizaria muito tempo no final):

  • Grande investimento. Para casos simples você perde cerca de 20% da implementação real, mas para casos complicados você perde muito mais.
  • Complexidade Adicional. Para casos complexos, seus casos de teste são mais difíceis de calcular, sugiro em casos como esse tentar usar código de referência automático que será executado em paralelo na versão de depuração/execução de teste, em vez do teste de unidade dos casos mais simples.
  • Impactos do projeto. Às vezes, o design não é claro no início e evolui à medida que você avança - isso forçará você a refazer o teste, o que gerará uma grande perda de tempo.Eu sugeriria adiar os testes unitários neste caso até que você tenha alguma noção do design em mente.
  • Ajustes Contínuos. Para estruturas de dados e algoritmos de caixa preta, os testes unitários seriam perfeitos, mas para algoritmos que tendem a ser alterados, ajustados ou ajustados, isso pode causar um grande investimento de tempo que se pode afirmar não ser justificado.Portanto, use-o quando achar que ele realmente se adapta ao sistema e não force o design a se ajustar ao TDD.

Outras dicas

Se você quiser fazer TDD "real" (leia:teste primeiro com as etapas vermelha, verde e de refatoração), então você também deve começar a usar mocks/stubs, quando quiser testar pontos de integração.

Ao começar a usar mocks, depois de um tempo, você desejará começar a usar Injeção de Dependência (DI) e um contêiner de Inversão de Controle (IoC).Para fazer isso, você precisa usar interfaces para tudo (que apresentam muitas armadilhas).

No final do dia, você tem que escrever muito mais código, do que se você simplesmente fizesse isso da "maneira antiga".Em vez de apenas uma classe de cliente, você também precisa escrever uma interface, uma classe simulada, algumas configurações de IoC e alguns testes.

E lembre-se de que o código de teste também deve ser mantido e cuidado.Os testes devem ser tão legíveis quanto todo o resto e leva tempo para escrever um bom código.

Muitos desenvolvedores não entendem muito bem como fazer tudo isso "da maneira certa".Mas como todo mundo lhes diz que o TDD é a única maneira verdadeira de desenvolver software, eles simplesmente tentam o melhor que podem.

É muito mais difícil do que se imagina.Muitas vezes projetos feitos com TDD acabam com muito código que ninguém realmente entende.Os testes unitários geralmente testam a coisa errada, da maneira errada.E ninguém concorda como deve ser um bom teste, nem mesmo os chamados gurus.

Todos esses testes tornam muito mais difícil "mudar" (em oposição à refatoração) o comportamento do seu sistema e mudanças simples tornam-se muito difíceis e demoradas.

Se você ler a literatura sobre TDD, sempre há alguns exemplos muito bons, mas muitas vezes em aplicações da vida real, você deve ter uma interface de usuário e um banco de dados.É aqui que o TDD fica realmente difícil e a maioria das fontes não oferece boas respostas.E se o fizerem, sempre envolve mais abstrações:objetos simulados, programação para uma interface, padrões MVC/MVP etc., que novamente exigem muito conhecimento, e...você precisa escrever ainda mais código.

Por isso tem cuidado...se você não tem uma equipe entusiasmada e pelo menos um desenvolvedor experiente que saiba escrever bons testes e também saiba algumas coisas sobre boa arquitetura, você realmente precisa pensar duas vezes antes de seguir o caminho do TDD.

Quando você chega ao ponto em que tem um grande número de testes, alterar o sistema pode exigir a reescrita de alguns ou de todos os seus testes, dependendo de quais foram invalidados pelas alterações.Isso poderia transformar uma modificação relativamente rápida em uma modificação muito demorada.

Além disso, você pode começar a tomar decisões de design com base mais em TDD do que em princípios de design realmente bons.Embora você possa ter uma solução muito simples e fácil, impossível de testar da maneira que o TDD exige, agora você tem um sistema muito mais complexo e, na verdade, mais sujeito a erros.

Acho que o maior problema para mim é a ENORME perda de tempo que leva para "entrar nisso".Ainda estou no início da minha jornada com o TDD (veja meu blog para atualizações de minhas aventuras de teste, se você estiver interessado) e eu literalmente gastei horas começando.

Leva muito tempo para colocar seu cérebro no “modo de teste” e escrever “código testável” é uma habilidade em si.

TBH, eu respeitosamente discordo Comentários de Jason Cohen sobre tornar públicos os métodos privados, não é disso que se trata. Não tornei mais métodos públicos em minha nova maneira de trabalhar do que antes.No entanto, envolve mudanças arquitetônicas e permite que você faça "hot plug" de módulos de código para tornar todo o resto mais fácil de testar.Você deve não estar tornando o interior do seu código mais acessível para fazer isso.Caso contrário, voltaremos à estaca zero com tudo sendo público, onde está o encapsulamento nisso?

Então, (IMO) em poucas palavras:

  • A quantidade de tempo necessária para pensar (ou seja,na verdade grocando testando).
  • O novo conhecimento exigia saber como escrever código testável.
  • Compreender as mudanças arquitetônicas necessárias para tornar o código testável.
  • Aumentando sua habilidade de "TDD-Coder" enquanto tenta melhorar todas as outras habilidades necessárias para nossa gloriosa arte de programação :)
  • Organizando sua base de código para incluir código de teste sem estragar seu código de produção.

PS:Se você quiser links para pontos positivos, fiz e respondi várias perguntas sobre isso, confira meu perfil.

Nos poucos anos em que pratico Desenvolvimento Orientado a Testes, devo dizer que as maiores desvantagens são:

Vendendo para a gerência

TDD é melhor executado em pares.Por um lado, é difícil resistir ao impulso de apenas escrever a implementação quando você SABER como escrever um se/outro declaração.Mas um par irá mantê-lo concentrado porque você o mantém concentrado.Infelizmente, muitas empresas/gestores não acham que este seja um bom uso de recursos.Por que pagar para duas pessoas escreverem um recurso, quando tenho dois recursos que precisam ser feitos ao mesmo tempo?

Vendendo para outros desenvolvedores

Algumas pessoas simplesmente não têm paciência para escrever testes unitários.Alguns estão muito orgulhosos de seu trabalho.Ou alguns apenas gostam de ver métodos/funções complicados vazando do final da tela.TDD não é para todos, mas eu realmente gostaria que fosse.Isso tornaria a manutenção das coisas muito mais fácil para as pobres almas que herdam o código.

Manter o código de teste junto com seu código de produção

Idealmente, seus testes só serão interrompidos quando você tomar uma decisão incorreta sobre o código.Ou seja, você pensou que o sistema funcionava de uma maneira e descobriu que não.Ao quebrar um teste, ou um (pequeno) conjunto de testes, isso é realmente uma boa notícia.Você sabe exatamente como seu novo código afetará o sistema.No entanto, se seus testes forem mal escritos, fortemente acoplados ou, pior ainda, gerados (tosse VS Test), então manter seus testes pode se tornar um coro rapidamente.E, depois que testes suficientes começarem a causar mais trabalho do que o valor percebido que estão criando, então os testes serão a primeira coisa a ser excluída quando os cronogramas ficarem comprimidos (por exemplo,chega a hora da crise)

Escrever testes para cobrir tudo (100% de cobertura de código)

O ideal, novamente, se você aderir à metodologia, seu código será 100% testado por padrão.Normalmente, pensei, acabo com uma cobertura de código superior a 90%.Isso geralmente acontece quando tenho alguma arquitetura de estilo de template, e a base é testada, e tento cortar atalhos e não testar as customizações do template.Além disso, descobri que quando encontro uma nova barreira que não havia encontrado anteriormente, tenho uma curva de aprendizado para testá-la.Admito que escrevi algumas linhas de código à moda antiga, mas gosto muito de ter isso 100%.(Acho que fui um empreendedor exagerado na escola).

No entanto, com isso eu diria que os benefícios do TDD superam em muito os negativos pela simples ideia de que se você conseguir um bom conjunto de testes que cubram sua aplicação, mas não sejam tão frágeis a ponto de uma alteração quebrar todos eles, você irá ser capaz de continuar adicionando novos recursos no dia 300 do seu projeto, como fez no dia 1.Isso não acontece com todos aqueles que tentam TDD pensando que é uma solução mágica para todos os seus códigos cheios de bugs, e então eles pensam que não pode funcionar, ponto final.

Pessoalmente, descobri que com o TDD escrevo código mais simples, gasto menos tempo debatendo se uma determinada solução de código funcionará ou não e não tenho medo de alterar qualquer linha de código que não atenda aos critérios estabelecidos por O time.

TDD é uma disciplina difícil de dominar, já estou nisso há alguns anos e ainda aprendo novas técnicas de teste o tempo todo.É um grande investimento de tempo inicial, mas, no longo prazo, sua sustentabilidade será muito maior do que se você não tivesse testes unitários automatizados.Agora, se ao menos meus chefes pudessem descobrir isso.

No seu primeiro projeto TDD há duas grandes perdas, tempo e liberdade pessoal

Você perde tempo porque:

  • A criação de um conjunto abrangente, refatorado e de fácil manutenção de testes unitários e de aceitação acrescenta muito tempo à primeira iteração do projeto.Isso pode ser uma economia de tempo a longo prazo, mas também pode ser um tempo que você não tem de sobra.
  • Você precisa escolher e se tornar especialista em um conjunto básico de ferramentas.Uma ferramenta de teste unitário precisa ser complementada por algum tipo de estrutura de simulação e ambas precisam se tornar parte do seu sistema de construção automatizado.Você também deseja escolher e gerar métricas apropriadas.

Você perde a liberdade pessoal porque:

  • TDD é uma forma muito disciplinada de escrever código que tende a atrapalhar aqueles que estão no topo e na base da escala de habilidades.Sempre escrever código de produção de uma determinada maneira e submeter seu trabalho à revisão contínua por pares pode assustar seus piores e melhores desenvolvedores e até mesmo levar à perda de funcionários.
  • A maioria dos métodos ágeis que incorporam TDD exigem que você converse continuamente com o cliente sobre o que você propõe realizar (nesta história/dia/qualquer que seja) e quais são as compensações.Mais uma vez, isso não agrada a todos, tanto do lado dos desenvolvedores quanto dos clientes.

Espero que isto ajude

O TDD exige que você planeje como suas classes funcionarão antes de escrever o código para passar nesses testes.Isso é um ponto positivo e um ponto negativo.

Acho difícil escrever testes em um "vácuo" - antes de qualquer código ser escrito.Na minha experiência, tenho tendência a tropeçar nos meus testes sempre que inevitavelmente penso em algo enquanto escrevo as minhas aulas que esqueci ao escrever os meus testes iniciais.Então é hora de refatorar não apenas minhas aulas, mas TAMBÉM meus testes.Repita isso três ou quatro vezes e pode ser frustrante.

Prefiro escrever primeiro um rascunho das minhas aulas e depois escrever (e manter) uma bateria de testes unitários.Depois de ter um rascunho, o TDD funciona bem para mim.Por exemplo, se um bug for relatado, escreverei um teste para explorar esse bug e, em seguida, corrigirei o código para que o teste seja aprovado.

A prototipagem pode ser muito difícil com TDD - quando você não tem certeza de qual caminho seguirá para chegar a uma solução, escrever os testes antecipadamente pode ser difícil (além dos muito amplos).Isso pode ser uma dor.

Honestamente, não acho que para o "desenvolvimento central" da grande maioria dos projetos haja alguma desvantagem real;isso é falado muito mais do que deveria, geralmente por pessoas que acreditam que seu código é bom o suficiente para não precisar de testes (nunca é) e pessoas que simplesmente não se dão ao trabalho de escrevê-los.

Bom, e esse alongamento, você precisa depurar seus testes.Além disso, há um certo custo de tempo para escrever os testes, embora a maioria das pessoas concorde que é um investimento inicial que compensa ao longo da vida útil do aplicativo, tanto em economia de tempo de depuração quanto em estabilidade.

O maior problema que tive pessoalmente com isso, porém, foi criar disciplina para realmente escrever os testes.Numa equipa, especialmente numa equipa estabelecida, pode ser difícil convencê-los de que o tempo gasto vale a pena.

Se seus testes não forem muito completos, você poderá cair na falsa sensação de "tudo funciona" só porque seus testes foram aprovados.Teoricamente, se seus testes forem aprovados, o código estará funcionando;mas se pudéssemos escrever código perfeitamente na primeira vez, não precisaríamos de testes.A moral aqui é fazer uma verificação de sanidade por conta própria antes de concluir algo, não confie apenas nos testes.

Por falar nisso, se sua verificação de sanidade encontrar algo que não foi testado, volte e escreva um teste para isso.

A desvantagem do TDD é que ele geralmente está fortemente associado à metodologia “Ágil”, o que coloca não importância na documentação de um sistema, em vez disso, o entendimento por trás de por que um teste 'deveria' retornar um valor específico em vez de qualquer outro reside apenas na cabeça do desenvolvedor.

Assim que o desenvolvedor abandona ou esquece o motivo pelo qual o teste retorna um valor específico e não outro, você está ferrado.TDD está bem SE estiver adequadamente documentado e cercado por arquivos legíveis por humanos (ou seja,documentação do gerenciador de cabelos pontudos) que poderá ser consultada em 5 anos, quando o mundo mudar e seu aplicativo também precisar.

Quando falo de documentação, isso não é uma sinopse de código, é um texto oficial que existe fora do aplicativo, como casos de uso e informações básicas que podem ser consultadas por gerentes, advogados e pelo pobre coitado que precisa atualizar seu código em 2011.

Já encontrei diversas situações em que o TDD me deixa louco.Para citar alguns:

  • Manutenção do caso de teste:

    Se você estiver em uma grande empresa, é provável que você não precise escrever os casos de teste sozinho ou pelo menos a maioria deles seja escrita por outra pessoa quando você entra na empresa.Os recursos de um aplicativo mudam de tempos em tempos e se você não tiver um sistema instalado, como o HP Quality Center, para rastreá-los, você ficará louco rapidamente.

    Isso também significa que os novos membros da equipe levarão bastante tempo para entender o que está acontecendo com os casos de teste.Por sua vez, isto pode ser traduzido em mais dinheiro necessário.

  • Complexidade da automação de teste:

    Se você automatizar alguns ou todos os casos de teste em scripts de teste executáveis ​​por máquina, terá que garantir que esses scripts de teste estejam sincronizados com seus casos de teste manuais correspondentes e alinhados com as alterações do aplicativo.

    Além disso, você gastará tempo para depurar os códigos que ajudam a detectar bugs.Na minha opinião, a maioria desses bugs vem da falha da equipe de teste em refletir as alterações do aplicativo no script de teste de automação.Mudanças na lógica de negócios, GUI e outras coisas internas podem fazer com que seus scripts parem de ser executados ou sejam executados de maneira não confiável.Às vezes, as mudanças são muito sutis e difíceis de detectar.Uma vez que todos os meus scripts relataram falha porque basearam seus cálculos nas informações da tabela 1, enquanto a tabela 1 agora era a tabela 2 (porque alguém trocou o nome dos objetos da tabela no código do aplicativo).

O maior problema são as pessoas que não sabem escrever testes unitários adequados.Eles escrevem testes que dependem um do outro (e funcionam muito bem rodando com Ant, mas de repente falham quando eu os executo no Eclipse, só porque eles rodam em ordem diferente).Eles escrevem testes que não testam nada em particular - eles apenas depuram o código, verificam o resultado e o transformam em teste, chamando-o de "teste1".Eles ampliam o escopo de classes e métodos, apenas porque será mais fácil escrever testes unitários para eles.O código dos testes unitários é terrível, com todos os problemas clássicos de programação (acoplamento pesado, métodos com 500 linhas, valores codificados, duplicação de código) e é um inferno de manter.Por alguma estranha razão, as pessoas tratam os testes unitários como algo inferior ao código "real" e não se importam nem um pouco com sua qualidade.:-(

Você perde muito tempo escrevendo testes.Claro, isso pode ser salvo até o final do projeto, detectando bugs mais rapidamente.

Você perde a capacidade de dizer que "concluído" antes de testar todo o seu código.

Você perde a capacidade de escrever centenas ou milhares de linhas de código antes de executá-lo.

Você perde a oportunidade de aprender por meio da depuração.

Você perde a flexibilidade de enviar códigos dos quais não tem certeza.

Você perde a liberdade de acoplar firmemente seus módulos.

Você perde a opção de pular a escrita da documentação de design de baixo nível.

Você perde a estabilidade que acompanha o código que todos têm medo de alterar.

Você perde o título de "hacker".

A maior desvantagem é que se você realmente quiser fazer o TDD corretamente, terá que falhar muito antes de ter sucesso.Considerando quantas empresas de software trabalham (dólar por KLOC), você acabará sendo demitido.Mesmo que seu código seja mais rápido, mais limpo, mais fácil de manter e tenha menos bugs.

Se você está trabalhando em uma empresa que paga pelos KLOCs (ou requisitos implementados - mesmo que não testados), fique longe de TDD (ou revisões de código, ou programação em pares, ou Integração Contínua, etc.etc.etc.).

Apoio a resposta sobre o tempo de desenvolvimento inicial.Você também perde a capacidade de trabalhar confortavelmente sem a segurança dos testes.Também fui descrito como um maluco do TDD, então você pode perder alguns amigos;)

Concentrar-se novamente em requisitos difíceis e imprevistos é a constante desgraça do programador.O desenvolvimento orientado a testes força você a se concentrar nos requisitos mundanos e já conhecidos e limita seu desenvolvimento ao que já foi imaginado.

Pense nisso, é provável que você acabe projetando casos de teste específicos, então não será criativo e começará a pensar "seria legal se o usuário pudesse fazer X, Y e Z".Portanto, quando esse usuário começar a ficar entusiasmado com os possíveis requisitos interessantes X, Y e Z, seu design poderá estar muito rigidamente focado em casos de teste já especificados e será difícil de ajustar.

Isto, claro, é uma faca de dois gumes.Se você gastar todo o seu tempo projetando para cada X, Y e Z concebível e imaginável que um usuário possa desejar, inevitavelmente nunca concluirá nada.Se você concluir algo, será impossível para qualquer pessoa (inclusive você) ter alguma ideia do que você está fazendo em seu código/design.

É percebido como mais lento.A longo prazo, isso não é verdade em termos de sofrimento, isso o salvará no futuro, mas você acabará escrevendo mais código, então, sem dúvida, estará gastando tempo "testando, não codificando".É um argumento falho, mas você perguntou!

Pode ser difícil e demorado escrever testes para dados "aleatórios", como feeds XML e bancos de dados (não tão difícil).Ultimamente, passei algum tempo trabalhando com feeds de dados meteorológicos.É bastante confuso escrever testes para isso, pelo menos porque não tenho muita experiência com TDD.

Você perderá turmas grandes com múltiplas responsabilidades.Você provavelmente também perderá métodos grandes com múltiplas responsabilidades.Você pode perder alguma capacidade de refatorar, mas também perderá parte da necessidade de refatorar.

Jason Cohen disse algo como:O TDD requer uma certa organização para o seu código.Isso pode estar arquitetonicamente errado;por exemplo, como os métodos privados não podem ser chamados fora de uma classe, é necessário tornar os métodos não privados para torná-los testáveis.

Digo que isso indica uma abstração perdida - se o código privado realmente precisa ser testado, provavelmente deveria estar em uma classe separada.

David Mann

Você precisa escrever aplicativos de uma maneira diferente:aquele que os torna testáveis.Você ficaria surpreso com o quão difícil isso é no início.

Algumas pessoas acham muito difícil pensar sobre o que vão escrever antes de escrever.Conceitos como zombaria também podem ser difíceis para alguns.TDD em aplicativos legados pode ser muito difícil se não forem projetados para teste.TDD em torno de estruturas que não são compatíveis com TDD também pode ser uma luta.

TDD é uma habilidade que os desenvolvedores juniores podem ter dificuldades no início (principalmente porque não foram ensinados a trabalhar dessa maneira).

No geral, porém, os contras são resolvidos à medida que as pessoas se tornam habilidosas e você acaba abstraindo o código 'fedorento' e tem um sistema mais estável.

Leva algum tempo para entrar nisso e algum tempo para começar a fazer isso em um projeto, mas...Sempre me arrependo de não ter adotado uma abordagem Test Driven quando encontro bugs bobos que um teste automatizado poderia ter encontrado muito rapidamente.Além disso, o TDD melhora a qualidade do código.

  • teste de unidade exige mais código para escrever, portanto, um custo inicial de desenvolvimento mais alto
  • é mais código para manter
  • aprendizagem adicional necessária

Boas respostas a todas.Eu acrescentaria algumas maneiras de evitar o lado negro do TDD:

  • Eu escrevi aplicativos para fazer seu próprio autoteste aleatório.O problema de escrever testes específicos é que mesmo que você escreva muitos deles, eles cobrem apenas os casos que você pensa.Geradores de testes aleatórios encontram problemas nos quais você não imaginou.

  • Todo o conceito de muitos testes unitários implica que você tem componentes que podem entrar em estados inválidos, como estruturas de dados complexas.Se você ficar longe de estruturas de dados complexas, haverá muito menos para testar.

  • Na medida em que seu aplicativo permitir, tenha cuidado com o design que depende da ordem adequada de notificações, eventos e efeitos colaterais.Eles podem cair facilmente ou serem mexidos, por isso precisam de muitos testes.

O TDD requer uma certa organização para o seu código.Isso pode ser ineficiente ou difícil de ler.Ou mesmo arquitetonicamente errado;por exemplo, desde private métodos não podem ser chamados fora de uma classe, você precisa tornar os métodos não privados para torná-los testáveis, o que é errado.

Quando o código muda, você também precisa alterar os testes.Com a refatoração, isso pode ser muito trabalho extra.

Deixe-me acrescentar que se você aplicar os princípios do BDD a um projeto TDD, poderá aliviar algumas das principais desvantagens listadas aqui (confusão, mal-entendidos, etc.).Se você não está familiarizado com o BDD, leia a introdução de Dan North.Ele criou o conceito em resposta a algumas questões que surgiram com a aplicação do TDD no local de trabalho.A introdução de Dan ao BDD pode ser encontrada aqui.

Só faço essa sugestão porque o BDD aborda alguns desses pontos negativos e atua como uma barreira.Você deve considerar isso ao coletar seu feedback.

Você tem que ter certeza de que seus testes estão sempre atualizados, o momento em que você começa a ignorar as luzes vermelhas é o momento em que os testes perdem o sentido.

Você também precisa ter certeza de que os testes são abrangentes, ou no momento em que um grande bug aparecer, o tipo de gerenciamento abafado que você finalmente convenceu a deixar você gastar tempo escrevendo mais código irá reclamar.

A pessoa que ensinou desenvolvimento ágil à minha equipe não acreditava em planejamento, você só escrevia isso para os menores requisitos.

Seu lema era refatorar, refatorar, refatorar.Passei a entender que refatorar significava 'não planejar com antecedência'.

O tempo de desenvolvimento aumenta:Todo método precisa de testes e, se você tiver um aplicativo grande com dependências, precisará preparar e limpar seus dados para testes.

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