Quando o teste de unidade é inadequado ou desnecessário? [duplicado]

98

Parece ser geralmente assumido (no Stack Overflow pelo menos) que deve sempre haver testes unitários, e eles devem ser mantidos atualizados. Mas eu suspeito que os programadores que fazem essas asserções trabalhem em diferentes tipos de projetos de mim - eles trabalham com software de alta qualidade, duradouro e enviado, onde os bugs são realmente ruins.

Se esse é o fim do espectro onde o teste unitário é mais valioso, então qual é o outro lado? Onde os testes de unidade são menos valiosos? Em que situações você não se incomodaria? Onde o esforço de manter testes não valeria o custo?

    
por Steve Bennett 05.05.2012 / 14:14
fonte

16 respostas

97

Eu pessoalmente não escrevo testes de unidade para situações em que:

  1. O código não possui ramificações é trivial. Um getter que retorna 0 não precisa ser testado e as alterações serão cobertas por testes para seus consumidores.

  2. O código simplesmente passa para uma API estável. Eu assumirei que a biblioteca padrão funciona corretamente.

  3. O código precisa interagir com outros sistemas implantados; então um teste de integração é chamado.

  4. Se o teste de sucesso / fracasso é algo que é tão difícil de quantificar para não ser mensurável de forma confiável, como a esteganografia sendo imperceptível para os seres humanos.

  5. Se o teste em si é uma ordem de magnitude mais difícil de escrever do que o código.

  6. Se o código for código descartável ou de espaço reservado. Se houver alguma dúvida, teste.

por 28.09.2014 / 20:06
fonte
67

A menos que você escreva código sem testá-lo, você sempre incorrerá no custo do teste.

A diferença entre ter testes de unidade e não tê-los é a diferença entre o custo de escrever o teste e o custo de executá-lo em comparação com o custo do teste manual.

Se o custo de escrever um teste de unidade for de 2 minutos e o custo de execução do teste de unidade for praticamente 0, mas o custo de testar manualmente o código for 1 minuto, você quebrará mesmo depois de executar o teste duas vezes.

Por muitos anos, fiquei sem entender que não tinha tempo suficiente para escrever testes de unidade para o meu código. Quando eu escrevia testes, eles estavam inchados, coisas pesadas que só me encorajavam a pensar que eu só deveria escrever testes de unidade quando eu soubesse que eles eram necessários.

Recentemente, fui encorajado a usar o Test Driven Development e descobri que era uma revelação completa. Agora estou firmemente convencido de que não tenho o tempo não para escrever testes unitários.

Na minha experiência, desenvolvendo com testes em mente você acaba com interfaces mais limpas, classes mais focadas & módulos e geralmente mais SOLID , código testável.

Toda vez que eu trabalho com código legado que não tem testes de unidade e eu tenho que testar manualmente algo, eu continuo pensando "isso seria muito mais rápido se esse código já tivesse testes de unidade". Toda vez que eu tenho que tentar adicionar funcionalidade de teste de unidade ao código com alto acoplamento, eu continuo pensando "isso seria muito mais fácil se tivesse sido escrito de uma forma desacoplada".

Comparando e contrastando as duas estações experimentais que eu suporto. Um já existe há algum tempo e tem muito código legado, enquanto o outro é relativamente novo.

Ao adicionar funcionalidade ao antigo laboratório, muitas vezes é preciso ir ao laboratório e passar muitas horas trabalhando com as implicações das funcionalidades de que precisam e como posso adicionar essa funcionalidade sem afetar nenhuma das outras funcionalidades. O código simplesmente não está configurado para permitir testes off-line, então praticamente tudo tem que ser desenvolvido on-line. Se eu tentasse desenvolver off-line, acabaria com mais objetos simulados do que seria razoável.

No laboratório mais novo, geralmente posso adicionar funcionalidade, desenvolvendo-a off-line na minha mesa, zombando apenas das coisas que são imediatamente necessárias e, em seguida, gastando pouco tempo no laboratório, resolvendo todos os problemas restantes. pegou off-line.

TL; DR versão:

Escreva um teste quando o custo de escrever o teste, mais o custo de executá-lo tantas vezes quantas forem necessárias, provavelmente será menor do que o custo de testá-lo manualmente quantas vezes precisar.

Lembre-se que se você usar o TDD, o custo de escrever testes provavelmente diminuirá à medida que você melhorar, e a menos que o código seja absolutamente trivial, você provavelmente acabará executando seus testes mais frequentemente do que o esperado.

    
por 08.05.2012 / 12:05
fonte
19

Pessoalmente, geralmente não escrevo testes de unidade para:

  • Alterações no código (legacy) não testado pela unidade existente. Embora, teoricamente, nunca seja tarde demais para iniciar o teste unitário, na prática, os ganhos da adição de testes unitários ao código nunca TDDed são pequenos. A única vantagem é a prevenção de regressão; você pode ver o efeito que uma alteração causa nas áreas que você pode ou não esperar que ela afete. No entanto, o teste de unidade só prova que o código ainda funciona da maneira que você fez quando você escreveu o teste; porque o teste não foi escrito com base nos requisitos originais, o teste não prova que a implementação atual está "correta". Fazer mudanças testadas na unidade em tal base de código é ainda mais um pesadelo na minha experiência do que simplesmente fazer a mudança e manualmente exercitar as áreas afetadas do programa; você primeiro tem que escrever um teste de unidade apropriado para o código em questão (que pode requerer refatoração do código para permitir zombaria e outras arquiteturas amigáveis ao TDD), provar que ele passa E que o refatorador não quebrou nada (e quando isso é o primeiro teste unitário já escrito para uma base de código de milhões de LoC, que pode ser difícil), então mude o teste para esperar algo diferente e mude o código para fazer o teste de mudança passar.

  • Layout da interface do usuário e comportamento de nível superior . Em alguns casos, isso não é viável; muitos IDEs com "designers" declaram elementos da interface do usuário como privados e não devem ser públicos conceitualmente. Torná-los internos exigiria colocar os testes de unidade nos mesmos conjuntos como código de produção (ruim) e torná-los protegidos exigiria um "proxy de teste" que expõe o que precisamos saber sobre os controles (geralmente não da maneira como é feito). Mesmo se fosse aceitável tornar todos os controles públicos e, portanto, ter acesso ao seu tipo, posição, propriedades de formatação, etc, os testes que verificam a interface do usuário são projetados da maneira esperada são extremamente frágeis. Geralmente, você ainda pode manipuladores de eventos de teste de unidade em codebehinds / viewmodels e, em seguida, é trivial provar que clicar no botão aciona o manipulador.

  • Persistência do banco de dados . Isto é, por definição, um teste de integração. Você sempre zomba do repositório ao lidar com código que transmite dados para o repositório, e você zomba dos ganchos do ORM ao desenvolver dentro do próprio repositório. Embora existam "testes de unidade de banco de dados" e você possa "simular" um banco de dados usando algo como o SQLite, acho que esses testes nunca se encaixam no nível da unidade.

  • Código de terceiros . Você testa SEU código como quiser e confia que os desenvolvedores das ferramentas de terceiros que você está usando (incluindo componentes do próprio .NET Framework como WPF, WCF, EF, etc.) fizeram o trabalho certo, até que se provaram errados. Um teste de unidade que prova que você faz a chamada WCF correta não requer realmente a passagem do proxy de serviço e não é necessário testar se uma chamada de serviço WCF específica funciona corretamente em um teste de unidade (se funciona ou não depende de variáveis específicas do ambiente que podem ser perfeitas em um ambiente de teste local, mas não no build-bot, ou nos ambientes QA, Staging ou UAT; é aí que a integração de nível superior, AAT e teste manual ainda têm valor) .

Em quase todos os outros casos, uma metodologia test-first tem valor significativo na aplicação de requisitos e YAGNI, impedindo a regressão, identificando conflitos de requisitos, etc. Mesmo em casos de código "trivial", essa verificação de que "sim, essa propriedade não ainda retorna este valor e assim você pode confiar que em outros testes "tem valor para mim como desenvolvedor.

    
por 07.05.2012 / 18:01
fonte
18

Existe um trade-off entre o custo de escrever testes unitários e o valor que eles adicionam. Negligenciar isso arrisca a possibilidade de excesso de testes .

blueberryfields abordou uma variável que afeta o valor dos testes unitários: estabilidade do projeto (ou ritmo de desenvolvimento). Eu gostaria de expandir isso.

O valor para ter testes de unidade segue aproximadamente o seguinte gráfico (yay, MS Paint!):

  1. Naprimeirazona,ocódigoéinstávelapontodeostestesdeunidadeprecisaremserreescritosoutotalmentedescartados.Issopodeserumprotótipoquevocêsabequenãoseráusado.Oupodeserumprojetoemquevocêénovonalinguagemdeprogramaçãoounoframework(egeralmenteprecisarefazergrandesquantidadesdecódigo).

    Testesdeunidadesãobonspararefatorarnoníveldomódulo(ouseja,alterarfunções).Oproblemaéquandoocódigoéinstávelnoníveldearquitetura,ondemódulosinteirospodemserreescritos,removidosoucompletamenteredesenhados.Ostestesunitáriosdevementãoseralterados/removidos/adicionados,oqueéumfardo.

    Nestafase,limitarostestesdeintegraçãononíveldosistema,oumesmootestemanual,éumaabordagemmelhor(qualvocêescolherádependernovamentedocustodeescreverotesteversusovalorobtido).

  2. Ostestesunitáriosadicionamomaiorvalornasegundazona,ondeocódigosetornaestávelacimadoníveldomódulo,masaindanãononíveldomódulo.Sevocêtemumabasedecódigoestáveleestáadicionandoummóduloquetemumagrandechancedepermanecer,issoéquandootestedeunidadeéumagrandevitória.

  3. Testesdeunidadetambémcomeçamatermenosvalorquandoaestabilidadedocódigoemtesteémuitoalta.Testaruminvólucrosimplesdeumafunçãodebibliotecapadrãoéumexemploemqueotestedeunidadeéumexagero.

    Seumtrechodecódigoquevocêestáescrevendoprovavelmentenuncaprecisaráseralterado,evocêestáconfiantedequeestácerto(talvezsejasupersimples?),hámenosvalorparaoteste.

Otestedeunidadesetornabenéficoquandoautilidadeémaiorqueocusto,comomostradonográficoabaixonazonaII.

Essa linha de custo pode estar em níveis diferentes para pessoas diferentes (linha 1 x linha 2). Se você é novo na estrutura de teste usada em um projeto, isso aumenta o nível e diminui o uso do net . Um custo mais alto (linha 2) reduz o intervalo em que o teste de unidade é apropriado.

A linha de custo não precisa necessariamente ser plana. Especialmente quando você considera outras variáveis, como tamanho do projeto, e se já existe uma estrutura de teste para o projeto, isso pode ser verdade.

    
por 12.04.2017 / 09:31
fonte
11

Where are unit tests least valuable?

Você deve estar escrevendo testes de unidade apenas para código lógico. A definição do código lógico está abaixo:

Código lógico é qualquer parte do código que tenha algum tipo de lógica, pequeno como pode ser. É um código lógico se tiver um ou mais dos seguinte: uma instrução IF, um loop, switch ou instruções de caso, cálculos, ou qualquer outro tipo de código de tomada de decisão.

If that's the end of the spectrum where unit testing is most valuable, then what's the other end?

  • Código totalmente acoplado não pode ser facilmente testado. Às vezes não pode ser testado. Por exemplo, os formulários da Web ASP.NET são um pesadelo e às vezes impossíveis de serem testados, ao contrário de ASP.NET MVC que é construído com o teste de unidade em mente.

  • Eu posso optar por não escrever testes para projetos muito pequenos e simples. Isso é perfeitamente justificável em um mundo com tempo e recursos limitados. Sim, é arriscado, mas é perfeitamente aceitável quando a empresa em que você trabalha tem um tempo limitado para o mercado.

What situations would you not bother? Where would the effort of maintaining tests not be worth the cost?

Uma vez que os testes de unidade estão no lugar, seu custo de manutenção se torna muito insignificante. Testes de unidade com alta cobertura de código dão a você um valioso senso de confiança de que o sistema se comporta como você espera. O mesmo se aplica aos testes de integração, mas essa não é sua pergunta.

Minha resposta é baseada nas seguintes suposições:

  • Você sabe a diferença entre testes unitários, de integração e funcionais.
  • Você é proficiente em uma das estruturas de teste de unidade, e é necessário muito pouco esforço para escrever um teste de unidade.
  • Você não sente que está fazendo um trabalho extra quando está escrevendo testes de unidade.

Referência: Arte de testes unitários

    
por 04.05.2012 / 21:58
fonte
9

Kent Beck (o homem por trás da ideia de Testes Unitários)

    
por 05.05.2012 / 22:34
fonte
7

Você realmente deve ter testes para qualquer código que pretenda executar em mais de uma ocasião.

Se você pretende executá-lo uma vez e depois descartá-lo, os testes podem não ser úteis, embora se o domínio for complexo, eu poderia escrever os testes de qualquer maneira para me ajudar com o design e a implementação.

Caso contrário, mesmo que a única coisa que os testes façam seja confirmar que suas suposições ainda estão corretas, elas são valiosas. E qualquer código que durar mais que uma única sessão precisará de modificações, e nesse ponto os testes se pagarão 10 vezes.

    
por 03.05.2012 / 12:57
fonte
6

Eu não tenho nenhuma ideia sobre desnecessário mas vou tentar quando penso que os Testes de Unidade são inapropriados porque acrescentam custo sem benefício proporcional:

Se a nossa equipe de desenvolvimento / organização não estiver fazendo nenhum teste de unidade, a menos que você seja capaz de convencer seus colegas desenvolvedores a executar testes de unidade (e também criar sozinhos), os testes que você criar não serão para ser executado e mantido. (Isso significa que você está trabalhando em um software junto com outra pessoa.)

Nem todo mundo está fazendo testes de unidade, eles às vezes são mal suportados pela cultura da equipe local, e em tais ambientes você primeiro precisa colocá-los em prática para a maioria dos desenvolvedores e provavelmente também para o processo de construção ("[contínuo] ] integração ") antes de começar a escrever testes de unidade faz sentido.

Dada a pressão do tempo e as datas de entrega e a "sua" posição relativa com a equipe - o tempo restante até que a escrita dos testes unitários faça sentido pode ser facilmente meses ou anos.

    
por 03.05.2012 / 13:55
fonte
4

Às vezes você não tem tempo para testar a unidade. Tudo bem.

Restrições externas existem e você pode não sentir a necessidade de testes em um determinado momento, pois você pode pensar que tem uma compreensão firme sobre o estado do sistema como um todo e saber como as mudanças irão fluir através dele.

Mas eu ainda acredito que você deveria sentir-se um pouco culpado sobre isso. Então, quando as coisas começam a desmoronar, você saberá que é porque: "oh, sim, eu não estou testando coisas, vamos começar a testar."

Antes desse momento, a sensação de culpa irá ajudá-lo a evitar certas escolhas de arquitetura que impedirão você de automatizar os testes de código posteriormente.

    
por 03.05.2012 / 14:40
fonte
2

O custo não está na manutenção de testes, mas sim em não manter o código de trabalho. Se você se divorciar do teste e da implementação, estará assumindo que o que você escreve funcionará sem o benefício da prova. Os testes fornecem essa prova e a confiança para manter o código com o passar do tempo. Claro que você pode pensar que você nunca vai revisitar o aplicativo que você pensou que era um lançamento, no entanto, a realidade é que qualquer tempo que você gasta escrevendo software é um investimento que seu empregador não quer tratar de ânimo leve. Vamos enfrentá-lo, os desenvolvedores de software geralmente não são baratos, e o tempo gasto em código para jogar fora é simplesmente dinheiro queimado para o seu empregador.

Se você está criando um problema, escrevendo algumas linhas de código para ver como algo funciona ou simplesmente juntando um exemplo para o Programmers.SE, então é realmente um caso de criar algo que você tem a intenção de jogar fora quando satisfez sua compreensão de um problema. Em tais casos, o teste de unidade pode ser um obstáculo para a tarefa e pode ser deixado de fora com segurança. Em todos os outros casos, no entanto, eu diria que o teste é sempre apropriado, mesmo que o programa pareça relativamente sem importância, e você sempre deve tentar escrever software em um padrão profissional com suporte de teste suficiente para reduzir a dificuldade de manter o código no futuro.

    
por 03.05.2012 / 12:54
fonte
1

A quantidade e a qualidade do teste unitário a ser feito em um projeto é diretamente proporcional ao ritmo de desenvolvimento e à estabilidade necessária do produto.

Em uma extremidade, para um script único, demonstração trivial ou em um ambiente de inicialização rápida durante os estágios iniciais, é improvável que os testes de unidade sejam importantes ou úteis para qualquer coisa. Eles são quase sempre, quase certamente, um desperdício de tempo e recursos.

No outro extremo, ao escrever software para controlar marcapassos, ou pilotar foguetes, ou ao trabalhar para manter sistemas de software estáveis e altamente complexos (digamos, um compilador com adoção pesada em todo o multiverso), várias camadas de unidade teste e outra cobertura são cruciais.

[Existem muitos outros fatores específicos da situação, cada um contribuindo de uma forma ou de outra, como o tamanho da sua equipe, seu orçamento, o talento de seus desenvolvedores, sua estratégia de desenvolvimento de software preferida, etc ... Geralmente, e no mais alto nível de abstração, acho que esses dois fazem a maior diferença]

    
por 04.05.2012 / 00:01
fonte
0

A meu ver, os protótipos de produto / código não exigem testes, pois geralmente são fornecidos usando um processo completamente diferente e com finalidades completamente diferentes de um produto acabado.

Imagine este cenário comum. Você tem algum tipo de tecnologia pela qual sua empresa é famosa, sua equipe de vendas ou um executivo chefe vai para um cliente e é capaz de vender um produto diferente que está alavancando sua tecnologia. Eles vendem lá e prometem ao cliente que verão uma versão beta em um mês. Você não tem nada, nem mesmo uma equipe de desenvolvimento.

O que acontece a seguir é que você projeta rapidamente uma solução baseada nos pontos acordados / vendidos ao cliente, monta uma equipe de engenheiros (geralmente estrelados) e começa a escrever o código. Seria ideal, claro, se as datas não fossem escorregadias (sempre acontecem) e você conseguisse escrever código em três semanas, em vez de quatro. Nesse caso, você tem uma semana extra e, se conseguiu garantir o tempo de uma equipe de controle de qualidade para essa semana, você a testará. Na realidade, você não terá uma semana extra e / ou sua equipe de QA será contratada por mais dois meses para apoiar outras entregas de produtos. Além disso, você não terá nenhuma especificação de projeto, então a equipe de controle de qualidade não fará a menor ideia do que eles devem testar. Então você acaba entregando o que você escreveu com um pouco de seu próprio teste de fumaça, o que não é realmente um teste como tal, simplesmente porque você não está qualificado para testar seu próprio código. O maior fator aqui é que o cliente verá algumas das funcionalidades prometidas muito rapidamente. Se o seu protótipo faz o trabalho, você volta para a prancheta, onde você projeta e planeja a versão 1.0 - desta vez corretamente.

No que diz respeito aos testes unitários, eles são bons para manter certos contratos (eu prometo que meu código fará isso, se não for - está quebrado). No caso de protótipos, você pode não se importar tanto com contratos, porque muitas vezes seus protótipos não vão viver para se tornar a versão 1.0, seja porque o cliente foi embora, ou porque você acabou desenvolvendo sua versão 1.0 usando diferentes tecnologias / ferramentas. Um exemplo aqui seria um site de protótipos rápido escrito muito rapidamente no PHP em um mês por uma pessoa, e então você monta uma equipe para reescrevê-lo no JEE. Até mesmo o banco de dados geralmente não sobrevive a essa mudança.

    
por 03.05.2012 / 12:43
fonte
0

Você deve escrever testes de unidade quando a compreensão lógica necessária para manter ou estender ou comunicar a lógica do aplicativo sem falhas exceder (ou provavelmente exceder no futuro) a capacidade do membro menos experiente de sua equipe de atender esse requisito. compreensão.

Basicamente depende de quanto você pode manter em sua cabeça de uma só vez. Por conta própria, você pode ter mais confiança de que pode codificar (com total conhecimento do impacto de suas alterações) até que uma certa complexidade seja atingida. Até esse ponto, os testes de unidade são uma distração, um obstáculo e atrasá-lo. Em uma equipe, o limite será muito menor, então você precisa de testes unitários imediatamente para combater a estupidez de grupo. Se você pegar um projeto sem provas de outra pessoa (ou se esquecer de um projeto de algum tempo atrás), você vai querer escrever testes unitários antes de mudar qualquer coisa, porque sua compreensão será zero.

Nota: escrever menos código e praticar YAGNI, diminui a complexidade e, consequentemente, o número de testes unitários necessários.

    
por 03.05.2012 / 14:14
fonte
0

Testes unitários são legais e tudo mais, mas em sistemas complicados com muitas "partes móveis", eles realmente não testam muito.

Como sabemos, testes unitários asseguram que, dada a entrada X para uma unidade, você obtém a saída Y, onde X é toda a entrada apropriada e Y é toda a saída apropriada. No entanto, acho que a maioria dos códigos faz o que o desenvolvedor achava que deveria ... mas não é necessário o que realmente deveria fazer.
(Você pode pensar nisso como uma arma. Uma arma tem um monte de peças de precisão fabricadas separadamente e depois montadas. Não importa se cada parte em particular é bem testada para funcionalidade se a arma explodir quando realmente disparada. : Eu não sei nada sobre armas de fogo (:)

Nesse caso, precisamos de testes reais do sistema em um ambiente de produção de modelo. Como a funcionalidade é testada aqui de qualquer maneira, o valor dos testes unitários é levemente diminuído.

No entanto, os testes de unidade ainda são valiosos nesse caso, pois fornecem a garantia de que a funcionalidade que você deseja manter inalterada permanece, de fato, inalterada. Isso é muito valioso porque lhe dá confiança para que as áreas do sistema precisem de testes focados.

    
por 03.05.2012 / 17:12
fonte
-1

Os testes unitários da IMO são inapropriados (não desnecessários!) em qualquer base de código onde seriam necessárias muitas horas de refatoração ou mesmo uma reescrita completa para introduzir testes unitários, porque seria muito difícil para a gerência permitir esse tempo de lotação.

    
por 03.05.2012 / 22:46
fonte
-1

Em uma organização menor e mais rápida, acho que os desenvolvedores são tão pressionados a permanecer produtivos e se movimentar rapidamente, que muitas vezes simplesmente não se incomodam em testar suas próprias alterações.

Temos uma política geral que afirma que, se você fizer uma alteração (seja uma correção ou aprimoramento de bug), o desenvolvedor deve testá-la antes de enviar o código para obter mais controle de qualidade.

Na verdade, não escrevemos testes de unidade para a maioria das instâncias porque nossas telas são na maioria das vezes projetadas de forma que, se uma alteração for feita na tela, o restante da lógica deve ser analisado para descobrir se a a mudança foi bem-sucedida independentemente.

Eu acho imperativo que o desenvolvedor faça seus próprios testes, seja documentado ou não, porque eles são os que melhor sabem onde os potenciais pontos fracos da lógica podem estar.

Então, eu diria que, mesmo que você não escreva testes unitários para cada pequena parte do sistema, testes de senso comum devem ser feitos independentemente.

    
por 12.05.2012 / 16:52
fonte