Diferença horária entre o desenvolvimento com testes unitários versus nenhum teste

130

Sou um desenvolvedor solo com um ambiente de trabalho bastante limitado pelo tempo, em que o tempo de desenvolvimento varia de 1 a 4 semanas por projeto, dependendo dos requisitos, da urgência ou de ambos. A qualquer momento, manejo cerca de 3-4 projetos, alguns com cronogramas que se sobrepõem.

Espera-se que a qualidade do código sofra. Eu também não tenho testes formais; geralmente vai até andar pelo sistema até que se rompa um pouco. Como resultado, uma quantidade considerável de bugs escapam para a produção, o que eu tenho que consertar e, por sua vez, define meus outros projetos.

É aqui que entra o teste de unidade. Quando feito corretamente, ele deve manter no mínimo os bugs, sem falar dos que fogem da produção. Por outro lado, escrever testes pode levar uma quantidade considerável de tempo, o que não soa bem com projetos com restrições de tempo como o meu.

A pergunta é, quanto de diferença de tempo seria escrever código testado por unidade sobre código não testado, e como essa diferença de tempo escala à medida que o escopo do projeto aumenta?

    
por Revenant 15.06.2016 / 04:37
fonte

12 respostas

144

Quanto mais tarde você testar, mais custa escrever testes.

Quanto mais tempo um bug vive, mais caro é consertar.

A lei dos retornos decrescentes garante que você possa testar a si mesmo até o esquecimento, tentando garantir que não haja bugs.

Buda ensinou a sabedoria do caminho do meio. Testes são bons. Existe algo de muito bom. A chave é saber quando você está desequilibrado.

Cada linha de código que você escreve sem testes terá custos significativamente maiores para adicionar testes mais tarde do que se você tivesse escrito os testes antes de escrever o código.

Cada linha de código sem testes será significativamente mais difícil de depurar ou reescrever.

Cada teste que você escreve leva tempo.

Cada bug levará tempo para corrigir.

O fiel lhe dirá para não escrever uma única linha de código sem primeiro escrever um teste com falha. O teste garante que você está recebendo o comportamento esperado. Ele permite que você altere o código rapidamente sem se preocupar em afetar o restante do sistema, pois o teste prova que o comportamento é o mesmo.

Você deve pesar tudo isso contra o fato de que os testes não adicionam recursos. Código de produção adiciona recursos. E os recursos são o que pagam as contas.

Pragmaticamente falando, eu adiciono todos os testes que posso fazer. Eu ignoro os comentários em favor de assistir a testes. Eu nem mesmo confio em código para fazer o que eu acho que faz. Eu confio em testes. Mas sou conhecido por jogar ocasionalmente granizo e ter sorte.

No entanto, muitos programadores bem sucedidos não fazem TDD. Isso não significa que eles não testem. Eles simplesmente não insistem obsessivamente que cada linha de código tenha um teste automatizado contra ela. Até mesmo o tio Bob admite que ele não testa sua interface do usuário. Ele também insiste em que você mova toda a lógica para fora da interface do usuário.

Como uma metáfora do futebol americano (que é o futebol americano), o TDD é um bom jogo de chão. O teste somente manual onde você escreve uma pilha de código e espera que funcione é um jogo de passagem. Você pode ser bom em qualquer um. Sua carreira não vai fazer os playoffs a menos que você possa fazer as duas coisas. Não fará o superbowl até que você aprenda quando escolher cada um. Mas se você precisar de um empurrão em uma direção específica: as ligações dos oficiais vão contra mim com mais frequência quando estou passando.

Se você quiser experimentar o TDD, recomendo que pratique antes de tentar fazê-lo no trabalho. TDD feito meio caminho, meio coração e meia boca é uma grande razão para alguns não respeitarem. É como derramar um copo de água no outro. Se você não se compromete e o faz de forma rápida e completa, acaba driblando a água por toda a mesa.

    
por 15.06.2016 / 05:17
fonte
111

Concordo com o resto das respostas, mas respondo à pergunta qual é a diferença de tempo diretamente.

Roy Osherove em seu livro A Arte de Testes Unitários, Segunda Edição página 200 fez um estudo de caso da implementação de projetos de tamanho similar com equipes semelhantes (habilidade) para dois clientes diferentes, onde uma equipe testou outro não.

Seus resultados foram assim:

Assim, no final de um projeto, você obtém menos tempo e menos bugs. Isso, obviamente, depende do tamanho do projeto.

    
por 15.06.2016 / 11:11
fonte
30

Há apenas um estudo que eu conheço que estudou isso em uma "configuração do mundo real": Realizando a melhoria da qualidade através do desenvolvimento orientado a testes: resultados e experiências de quatro equipes industriais . É caro fazer isso de uma maneira sensata, já que basicamente significa que você precisa desenvolver o mesmo software duas vezes (ou, idealmente, com mais frequência) com equipes semelhantes e, depois, jogar tudo menos uma delas.

Os resultados do estudo foram um aumento no tempo de desenvolvimento entre 15% e 35% (que está longe do valor de 2x que frequentemente é citado pelos críticos de TDD) e uma diminuição na densidade de defeitos pré-liberação de 40% -90 % (!). Note que todas as equipes não tinham experiência anterior com TDD, então pode-se supor que o aumento no tempo pode ser atribuído, pelo menos em parte, à aprendizagem e, portanto, diminuir ainda mais com o tempo, mas isso não foi avaliado pelo estudo. >

Note que este estudo é sobre TDD, e sua pergunta é sobre testes unitários, que são coisas muito diferentes, mas é o mais próximo que eu pude encontrar.

    
por 15.06.2016 / 10:44
fonte
24

Feito bem, o desenvolvimento com testes de unidade pode ser mais rápido mesmo sem considerar os benefícios de erros extras sendo capturados.

O fato é que eu não sou um bom codificador para simplesmente ter meu código funcionando assim que ele compila. Quando escrevo / modifico o código, tenho que executar o código para ter certeza de que ele faz o que eu acho que faz. Em um projeto, isso tendia a ficar parecido com:

  1. Modificar código
  2. Compilar aplicativo
  3. Executar aplicativo
  4. Faça login no aplicativo
  5. Abra uma janela
  6. Selecione um item dessa janela para abrir outra janela
  7. Defina alguns controles nessa janela e clique em um botão

E, claro, depois de tudo isso, costumava fazer algumas viagens de ida e volta para acertar.

Agora, e se eu estiver usando testes de unidade? Então o processo parece mais com:

  1. Escreva um teste
  2. Execute testes, verifique se ele falha da maneira esperada
  3. Escreva o código
  4. Execute os testes novamente, veja se ele passa

Isso é mais fácil e rápido do que testar manualmente o aplicativo. Eu ainda tenho que executar manualmente o aplicativo (para que eu não pareça bobo quando eu entrego o trabalho que realmente não funciona), mas na maioria das vezes eu já trabalhei com os problemas, e eu sou apenas verificando nesse ponto. Na verdade, normalmente faço esse loop ainda mais apertado usando um programa que automaticamente executa novamente meus testes quando salvo.

No entanto, isso depende do trabalho em uma base de código favorável ao teste. Muitos projetos, mesmo aqueles com muitos testes, dificultam os testes de escrita. Mas se você trabalhar nisso, você pode ter uma base de código que é mais fácil de testar através de testes automatizados do que com testes manuais. Como bônus, você pode manter os testes automatizados e continuar executando-os para evitar regressões.

    
por 15.06.2016 / 06:17
fonte
19

Apesar de já haver muitas respostas, elas são um tanto repetitivas e eu gostaria de ter uma abordagem diferente. Testes de unidade são valiosos, se e somente se , eles aumentam valor de negócio . Testar por testes (testes triviais ou tautológicos), ou para atingir alguma métrica arbitrária (como cobertura de código), é uma programação de cultos de carga.

Os testes são caros, não apenas no tempo necessário para escrevê-los, mas também na manutenção. Eles precisam ser mantidos em sincronia com o código que testam ou são inúteis. Sem mencionar o custo de tempo de executá-los em cada mudança. Isso não é uma quebra de acordo (ou uma desculpa para não fazer os realmente necessários), mas precisa ser levado em conta na análise de custo-benefício.

Então, a pergunta a ser feita ao decidir se deve ou não (ou de que tipo) testar uma função / método, pergunte a si mesmo 'qual valor do usuário final estou criando / salvaguardando com este teste?'. Se você não puder responder a essa pergunta, fora do topo da sua cabeça , então esse teste provavelmente não vale o custo de escrever / manter. (ou você não entende o domínio do problema, que é um problema waaaay maior do que a falta de testes).

link

    
por 15.06.2016 / 17:24
fonte
9

Depende da pessoa, assim como da complexidade e forma do código com o qual você está trabalhando.

Para mim, na maioria dos projetos, escrever testes unitários significa que eu trabalho 25% mais rápido. Sim, inclusive incluindo o tempo para escrever os testes.

Porque o fato é que o software não é feito quando você escreve o código. Isso é feito quando você o envia ao cliente e fica satisfeito com ele. Os testes de unidade são, de longe, a maneira mais eficiente de capturar a maioria dos bugs, isolar a maioria dos bugs para depuração e ganhar a confiança de que o código é bom. Você tem que fazer essas coisas anyways , então faça-as bem.

    
por 15.06.2016 / 05:26
fonte
4

Question is, how much of a time difference would writing unit-tested code over untested code, and how does that time difference scale as project scope widens?

O problema piora à medida que aumenta a idade do projeto: porque sempre que você adicionar novas funcionalidades e / ou sempre refatorar a implementação existente, você deve testar novamente o que foi previamente testado para garantir que ainda funcione. Portanto, para um projeto de longa duração (vários anos), talvez seja necessário não apenas testar a funcionalidade, mas testá-la novamente 100 vezes ou mais. Por esse motivo, você pode se beneficiar de testes automatizados . No entanto, o IMO é bom o suficiente (ou até melhor) se esses forem testes de sistema automatizados, em vez de testes unitários automatizados.

Um segundo problema é que os bugs podem ser mais difíceis de encontrar e consertar se não forem detectados cedo. Por exemplo, se houver um bug no sistema e eu souber que ele estava funcionando perfeitamente antes de você fazer sua última alteração, concentrei minha atenção na última alteração para ver como ele poderia ter introduzido o bug. Mas se eu não sei que o sistema estava funcionando antes de você fazer sua última alteração (porque o sistema não foi testado adequadamente antes de sua última alteração), então o bug pode estar em qualquer lugar.

O acima aplica-se especialmente ao código profundo e menos ao código superficial, por ex. adicionar novas páginas da web nas quais é improvável que novas páginas afetem as páginas existentes.

As a result, a considerable amount of bugs escape to production, which I have to fix and in turn sets back my other projects.

Na minha experiência, isso seria inaceitável e você está fazendo a pergunta errada. Em vez de perguntar se os testes tornariam o desenvolvimento mais rápido, você deveria perguntar o que tornaria o desenvolvimento mais livre de erros.

Uma pergunta melhor pode ser:

  • A unidade está testando o tipo certo de teste, o que você precisa para evitar a "quantidade considerável de bugs" que você está produzindo?
  • Existem outros mecanismos de controle / aprimoramento de qualidade (além do teste de unidade) para recomendar também ou em vez disso?

O aprendizado é um processo de dois estágios: aprenda a fazer bem o suficiente e aprenda a fazer isso mais rapidamente.

    
por 16.06.2016 / 15:40
fonte
3

Alguns aspectos a considerar, não mencionados nas outras respostas.

  • Benefício Extra / Custo Extra depende da experiência com os testes unitários escritos
    • com o meu primeiro projeto de teste unitário, os custos extras caíram porque eu tive que aprender muito e cometi muitos erros.
    • após 10 anos de experiência com o tdd eu preciso de 25% mais tempo de codificação para escrever os testes com antecedência.
  • com mais módulos tdd ainda há necessidade de teste manual de gui e teste de integração
  • tdd só funciona quando feito desde o começo.
    • aplicar o tdd a um projeto já existente é caro / dificultado. Mas você pode implementar testes de regressão.
  • testes automatizados (unittests e outros tipos de testes) exigem manutenção constante para mantê-los funcionando.
    • ter criado teste através de copiar e colar pode tornar testcode-maintanace caro.
    • com a crescente experiência, o testcode torna-se mais modular e mais fácil de manter.
  • com experiência crescente, você terá a sensação de que vale a pena criar testes automatizados e quando não.
    • exemplo, não há grande benefício em unittest getters / setters / wrappers simples
    • eu não escrevo testes automatizados através do gui
    • eu cuido para que o businesslayer possa ser testado

Resumo

Ao iniciar com o tdd, é difícil alcançar o estado "mais benefício do que custo", contanto que você esteja em "ambiente de trabalho com tempo limitado". especialmente se houver "gestores inteligentes" que lhe dizem para "se livrar do material de teste caro e inútil"

Nota: com "teste unitário", quero dizer "testando módulos isolados".

Nota: com "teste de regressão", quero dizer

  • escreva algum código que produza algum texto de saída.
  • escreva algum código de "teste de regressão" que verifique se o resultado da geração ainda é o mesmo.
  • o teste de regressão permite que você saiba sempre que o resultado for alterado (o que pode ser bom ou um indicador para um novo bug)
  • a ideia de "teste de regressão" é semelhante a testes de aprovação
    • ... tirando uma foto dos resultados e confirmando que eles não mudaram.
por 15.06.2016 / 13:55
fonte
3

Programadores, como pessoas que lidam com a maioria das tarefas, subestimam quanto tempo leva para concluí-lo. Com isso em mente, gastar 10 minutos para escrever um teste pode ser visto como o tempo que se poderia gastar escrevendo toneladas de código quando, na verdade, você gastaria esse tempo criando o mesmo nome de função e parâmetros que você fez durante o teste. . Este é um cenário de TDD.

Não escrever testes, é muito parecido com ter um cartão de crédito; nós tendemos a gastar mais ou escrever mais código. Mais código tem mais bugs.

Em vez de decidir ter uma cobertura de código total ou nenhuma, sugiro focar na parte crítica e complicada de seu aplicativo e ter testes lá. Em um aplicativo bancário, esse pode ser o cálculo de juros. Uma ferramenta de diagnóstico do motor pode ter protocolos de calibração complexos. Se você está trabalhando em um projeto, provavelmente sabe o que é e onde estão os bugs.

Comece devagar. Construa alguma fluência antes de julgar. Você sempre pode parar.

    
por 15.06.2016 / 14:09
fonte
3

Tem havido uma longa história de programadores promovendo o TDD e outras metodologias de testes, não vou me lembrar de seus argumentos e concordar com eles, mas aqui estão outras coisas a serem consideradas que devem ser refinadas:

  • O teste não é igualmente conveniente e eficiente dependendo do contexto. Eu desenvolvo software web, me diga se você tem um programa para testar toda a interface do usuário ... agora estou programando macros excel, devo realmente desenvolver um módulo de teste em VBA?
  • Escrever e manter o software de teste é um trabalho real que conta a curto prazo (vale a pena em uma execução mais longa). Escrever testes relevantes também é uma experiência para obter
  • Trabalhar em equipe e trabalhar sozinho não tem os mesmos requisitos de testes, pois na equipe você precisa validar, entender e comunicar o código que não escreveu.

Eu diria que o teste é bom, mas teste primeiro e teste onde está o ganho.

    
por 16.06.2016 / 13:51
fonte
1

Um benefício muitas vezes negligenciado do TDD é que os testes agem como uma proteção para garantir que você não esteja introduzindo novos bugs quando fizer uma alteração.

A abordagem do TDD é, sem dúvida, mais demorada inicialmente, mas o ponto final é que você vai escrever menos código , o que significa menos coisas para dar errado. Todos os sinos e assobios que você costuma incluir, como é óbvio, não serão incluídos na base de código.

Há uma cena no filme Swordfish, onde se a memória serve, um hacker está tendo que trabalhar com uma arma na cabeça e estar erm ... de outra forma distraído. O ponto é que é muito mais fácil trabalhar quando o headspace está no código e você tem tempo ao seu lado, em vez de meses, com um cliente gritando com você e outras prioridades sendo espremidas.

Desenvolvedores entendem que consertar bugs depois é mais caro, mas vire isso na cabeça. Se você pudesse receber US $ 500 por dia para codificar como você codifica agora, ou US $ 1.000 se você escrevesse de maneira TDD, você iria arrancar a mão da pessoa fazendo a segunda oferta. Quanto mais cedo você parar de ver o teste como uma tarefa e vê-lo como uma poupança de dinheiro, melhor você estará.

    
por 15.06.2016 / 12:26
fonte
0

Eu posso me relacionar com sua experiência - nossa base de código quase não tinha testes e era praticamente impossível de ser testada. Levou literalmente séculos para desenvolver algo e consertar erros de produção levou tempo precioso de novos recursos.

Para uma reescrita parcial, eu prometi escrever testes para todas as funcionalidades básicas. No início, demorou consideravelmente mais e a minha produtividade sofreu visivelmente, mas depois a minha produtividade foi melhor do que nunca.

Parte dessa melhoria foi que eu tinha menos erros de produção, o que por sua vez levava a menos interrupções - > Eu tive um foco melhor a qualquer momento.

Além disso, o potencial para testar e depurar código isoladamente realmente paga - um conjunto de testes é muito superior a um sistema que não pode ser depurado, exceto com a configuração manual, e. g. lançando seu aplicativo e navegue até a tela e faça algo ... talvez algumas dúzias de vezes

Mas note que há uma queda na produtividade no começo, então comece a aprender os testes em algum projeto onde a pressão de tempo já não é insana. Além disso, tente iniciá-lo em um projeto greenfield, o código herdado do teste de unidade é muito difícil e ajuda quando você sabe como é um bom conjunto de testes.

    
por 18.06.2016 / 17:41
fonte