Existe algo como ter muitos testes de unidade?

139

Fui encarregado de escrever testes de unidade para um aplicativo existente. Depois de terminar meu primeiro arquivo, tenho 717 linhas de código de teste para 419 linhas de código original.

Essa proporção se tornará incontrolável à medida que aumentamos nossa cobertura de código?

Minha compreensão do teste de unidade era testar cada método da classe para garantir que todos os métodos funcionassem conforme o esperado. No entanto, na solicitação de recebimento, meu líder técnico observou que eu deveria me concentrar em testes de nível superior. Ele sugeriu testar 4-5 casos de uso mais usados ​​com a classe em questão, em vez de testar exaustivamente cada função.

Confio no comentário do meu líder técnico. Ele tem mais experiência do que eu e tem melhores instintos quando se trata de projetar software. Mas como uma equipe de várias pessoas escreve testes para um padrão tão ambíguo; ou seja, como conheço meus colegas e compartilho a mesma idéia para os "casos de uso mais comuns"?

Para mim, 100% de cobertura de teste de unidade é uma meta elevada, mas mesmo que atingíssemos apenas 50%, saberíamos que 100% desses 50% estavam cobertos. Caso contrário, escrever testes para parte de cada arquivo deixa muito espaço para trapacear.

user2954463
fonte
145
Depende. Você está escrevendo um jogo de jogo da velha, ou está escrevendo código para gerenciar um reator nuclear?
Bryan Oakley
11
Com muitos testes de unidade, você pode detectar problemas de implementação de hardware exóticos, como o bug Pentium FDIV ou correlações em primitivas criptográficas, portanto, parece que não há um limite rígido passado que nenhum outro teste de unidade possa ser útil. Apenas um limite prático para quando é muito caro.
Nat
5
Testar em níveis mais altos fornecerá uma melhor perspectiva da cobertura real. Por cobertura real, quero dizer que é mais provável que ocorra durante o uso regular do sistema. Esse é o tipo de cobertura que você deseja obter primeiro. Nos 50% que chegam a alcançar, pode haver YAGNI ou código morto que, uma vez removido, também contribuirá para aumentar a cobertura geral.
Laiv 3/17/17
5
Se você fizer muitos testes (o que você parece não ter no momento), o problema mais provável é que o código que você está testando faz muito. Portanto, a responsabilidade única não é respeitada. Quando o código está bem dividido, o teste também não cria muito ônus. Se as aulas tiverem muitos efeitos colaterais, etc., isso se tornará um pesadelo.
Luc Franken
12
O documento de teste do sqlite é uma leitura divertida: sqlite.org/testing.html . Citação: "a biblioteca SQLite consiste em aproximadamente 122,9 KSLOC de código C. Em comparação, o projeto possui 745 vezes mais código de teste e scripts de teste - 91596.1 KSLOC."
User60561

Respostas:

180

Sim, com 100% de cobertura, você escreverá alguns testes desnecessários. Infelizmente, a única maneira confiável de determinar quais testes você não precisa é escrever todos eles, depois aguarde 10 anos ou mais para ver quais nunca falharam.

Manter muitos testes geralmente não é problemático. Muitas equipes têm testes automatizados de integração e sistema com 100% de cobertura de teste de unidade.

No entanto, você não está em uma fase de manutenção de teste, está tentando recuperar o atraso. É muito melhor ter 100% de suas aulas com 50% de cobertura de teste do que 50% de suas aulas com 100% de cobertura de teste, e seu líder parece estar tentando fazer com que você aloque seu tempo adequadamente. Depois de ter essa linha de base, a próxima etapa geralmente é pressionar 100% nos arquivos que serão alterados daqui para frente.

Karl Bielefeldt
fonte
11
Obrigado pela sua resposta. Isso ajudou a colocar minha pergunta em perspectiva e abordou o problema real - minha atitude! +1
user2954463
43
@astra Sua atitude não é tão ruim assim. É bom questionar o porquê. Para responder a sua outra pergunta, excelente pergunta: "Como conheço meus colegas e compartilho a mesma idéia para os" casos de uso mais comuns "? Você faz com que eles analisem seus testes. Veja os deles. Fale sobre eles. Você aprenderá . muito e testes talvez eles irão também Código revisão raramente é um desperdício de tempo Embora eu tendem a fazer o meu em um terminal, em vez de uma sala de conferências.
candied_orange
18
Um teste nunca falha em 10 anos nem sequer garante que seja necessário, ele pode acabar falhando em ano 11.
Pharap
24
Pragmaticamente, você pode adotar a abordagem oposta. Escreva os testes que você acha que abrangem os casos comuns. Porém, sempre que encontrar uma falha, escreva um teste para cobrir essa área.
Stannius
10
@Pharap Meu único problema com esta resposta é que existe a suposição implícita de que um teste só pode agregar valor quando falha. Um bom teste de unidade também fornece uma ótima forma de documentação viva. Ele também agregou valor quando você escreveu o teste, forçando-o a pensar em reutilização / composição / encapulação. Código não testado em minha experiência tende a ser bestas monolíticas inflexíveis.
ArTs 05/05
66

Se você trabalhou em grandes bases de código criadas usando o Test Driven Development, já saberia que pode haver muitos testes de unidade. Em alguns casos, a maior parte do esforço de desenvolvimento consiste em atualizar testes de baixa qualidade que seriam melhor implementados como verificações invariáveis, pré-condição e pós-condição nas classes relevantes, em tempo de execução (ou seja, testar como efeito colateral de um teste de nível superior) )

Outro problema é a criação de projetos de baixa qualidade, usando técnicas de projeto dirigidas por cultos de carga, que resultam em uma proliferação de coisas a serem testadas (mais classes, interfaces, etc.). Nesse caso, a carga pode parecer estar atualizando o código de teste, mas o verdadeiro problema é o design de baixa qualidade.

Frank Hileman
fonte
16
Votado para apontar pré-condições, pós-condições e invariantes deve ser tratado como teste de unidade. Dessa forma, todo uso é um teste de unidade quando esse código de depuração está ativo.
Persixty
Esta é uma ótima resposta e se alinha perfeitamente com a minha experiência.
Tony Ennis
E mais um problema: se você tiver fechado os check-ins (você realmente deveria!) Com grandes quantidades de baixa qualidade, possivelmente até mesmo os testes de execução longa tornarão tudo lento, sem fornecer benefícios reais. E então, obviamente, o fato divertido de você mudar uma coisa em uma classe e centenas de testes falharem.
Voo
3
Esta é uma resposta muito melhor do que a aceita! "Em alguns casos, a maior parte do esforço de desenvolvimento consiste em atualizar testes de baixa qualidade" - experimentei isso e é uma merda. Mais do que não ter testes, em alguns aspectos.
Benjamin Hodgson
36

Respostas às suas perguntas

Existe algo como ter muitos testes de unidade?

Claro ... Você pode, por exemplo, ter vários testes que parecem diferentes à primeira vista, mas realmente testam a mesma coisa (depende logicamente das mesmas linhas de código de aplicativo "interessante" em teste).

Ou você pode testar as partes internas do seu código que nunca surgem externamente (ou seja, não fazem parte de nenhum tipo de contrato de interface), onde se pode discutir se isso faz sentido. Por exemplo, o texto exato das mensagens de log internas ou o que for.

Fui encarregado de escrever testes de unidade para um aplicativo existente. Depois de terminar meu primeiro arquivo, tenho 717 linhas de código de teste para 419 linhas de código original.

Isso me parece bastante normal. Seus testes gastam muitas linhas de código na instalação e desmontagem, além dos testes reais. A proporção pode melhorar ou não. Eu próprio sou bastante pesado em testes e frequentemente investo mais tempo e local nos testes do que o código real.

Essa proporção se tornará incontrolável à medida que aumentamos nossa cobertura de código?

A proporção não leva em consideração tanto. Existem outras qualidades de testes que tendem a torná-los incontroláveis. Se você precisar refatorar regularmente vários testes ao fazer alterações bastante simples no seu código, dê uma boa olhada nos motivos. E essas não são quantas linhas você tem, mas como você aborda a codificação dos testes.

Minha compreensão do teste de unidade era testar cada método da classe para garantir que todos os métodos funcionassem conforme o esperado.

Isso é correto para testes "unitários" no sentido estrito. Aqui, "unidade" é algo como um método ou uma classe. O objetivo do teste "unitário" é testar apenas uma unidade específica de código, não o sistema inteiro. Idealmente, você removeria todo o resto do sistema (usando dobros ou outros enfeites).

No entanto, na solicitação de recebimento, meu líder técnico observou que eu deveria me concentrar em testes de nível superior.

Então você caiu na armadilha de supor que as pessoas realmente significavam testes de unidade quando diziam testes de unidade. Eu conheci muitos programadores que dizem "teste de unidade", mas significam algo bem diferente.

Ele sugeriu testar 4-5 casos de uso mais usados ​​com a classe em questão, em vez de testar exaustivamente cada função.

Claro, concentrar-se apenas nos 80% dos códigos importantes também reduz a carga ... Compreendo que você pense muito em seu chefe, mas isso não me parece a melhor opção.

Para mim, 100% de cobertura de teste de unidade é uma meta elevada, mas mesmo que atingíssemos apenas 50%, saberíamos que 100% desses 50% estavam cobertos.

Não sei o que é "cobertura de teste de unidade". Suponho que você queira dizer "cobertura de código", ou seja, depois de executar o conjunto de testes, todas as linhas de código (= 100%) foram executadas pelo menos uma vez.

Essa é uma boa métrica de estimativa, mas de longe não é o melhor padrão para o qual alguém poderia atirar. Apenas executar linhas de código não é a imagem toda; isso não leva em conta caminhos diferentes por meio de ramificações aninhadas e complicadas, por exemplo. É mais uma métrica que aponta o dedo para partes de código que são testadas muito pouco (obviamente, se uma classe tem 10% ou 5% de cobertura de código, algo está errado); por outro lado, uma cobertura de 100% não informa se você testou o suficiente ou se testou corretamente.

Teste de integração

Irrita-me substancialmente quando as pessoas estão constantemente falando sobre testes de unidade hoje, por padrão. Na minha opinião (e experiência), o teste de unidade é ótimo para bibliotecas / APIs; em áreas mais voltadas para negócios (onde falamos de casos de uso, como na pergunta em questão), elas não são necessariamente a melhor opção.

Para o código geral do aplicativo e para as empresas comuns (onde é importante ganhar dinheiro, cumprir prazos e satisfazer a satisfação do cliente, é importante evitar erros que estão diretamente na cara do usuário ou que podem levar a desastres reais - não estamos falando lançamentos de foguetes da NASA aqui), testes de integração ou de recursos são muito mais úteis.

Aqueles andam de mãos dadas com o Desenvolvimento Orientado ao Comportamento ou ao Desenvolvimento Orientado a Recursos; aqueles não funcionam com testes de unidade (estritos), por definição.

Para mantê-lo curto (ish), um teste de integração / recurso exercita toda a pilha de aplicativos. Em um aplicativo baseado na Web, ele funcionaria como um navegador clicando no aplicativo (e não, obviamente, não precisa ser tão simplista, existem estruturas muito poderosas para fazer isso - confira http: // pepino. io por exemplo).

Ah, para responder às suas últimas perguntas: você faz com que toda a sua equipe tenha uma alta cobertura de teste, certificando-se de que um novo recurso seja programado apenas após a implementação e falha do teste. E sim, isso significa todos os recursos. Isso garante uma cobertura de recurso 100% (positiva). Por definição, garante que um recurso do seu aplicativo nunca "desapareça". Ele não garante uma cobertura de código de 100% (por exemplo, a menos que você programe ativamente recursos negativos, não estará exercitando seu tratamento de erros / tratamento de exceções).

Ele não garante um aplicativo sem erros; é claro que você deseja escrever testes de recursos para situações de bugs óbvias ou muito perigosas, entrada incorreta do usuário, hackers (por exemplo, gerenciamento de sessões, segurança e outros) etc .; mas mesmo a programação dos testes positivos tem um tremendo benefício e é bastante viável com estruturas modernas e poderosas.

Os testes de recursos / integração obviamente têm sua própria lata de worms (por exemplo, desempenho; teste redundante de estruturas de terceiros; como você geralmente não usa duplos, eles também tendem a ser mais difíceis de escrever, na minha experiência ...), mas eu ' d use um aplicativo 100% testado por recurso positivo em vez de um aplicativo 100% testado por unidade de cobertura de código (não biblioteca!) a qualquer dia.

AnoE
fonte
1
Os testes de integração são ótimos, mas não substituem os testes de unidade, nem os aplicativos de negócios. Existem vários problemas com eles: a) eles, por definição, levam muito tempo para serem executados (isso também significa que testes incrementais são praticamente inúteis), b) eles tornam incrivelmente difícil identificar o problema real (oh 50 testes de integração simplesmente falharam, que mudança causou isso?) e c) eles cobrem os mesmos caminhos de código repetidamente.
Voo 5/05
1
a) é um problema porque dificulta a execução dos testes em check-ins fechados e torna menos provável que os programadores executem os testes repetidamente durante o desenvolvimento, o que, juntamente com b) diminui a eficiência e a capacidade de diagnosticar erros rapidamente. c) significa que mudar uma coisinha pode facilmente fazer com que dezenas ou centenas (presentes) de seus testes de integração falhem, o que significa que você gastará muito tempo consertando-os. Isso também significa que os testes de integração geralmente testam apenas caminhos felizes, porque escrever esses testes direcionados é complicado ou impossível.
Voo 5/05
1
@Voo, tudo o que você escreveu é verdade, e até onde eu sei, eu já mencionei todos os problemas que você anotou na resposta ... #
317 AnoE17
Se você concorda com esse resumo, realmente não vejo como você pode concluir que prefere testes de integração a testes de unidade. Conjuntos abrangentes de testes de integração de grandes programas levam horas ou até dias para serem executados, eles são ótimos de se ter, mas são praticamente inúteis durante o desenvolvimento real. E seus testes de aceitação (que todo mundo está fazendo, certo?) Capturam muitos dos mesmos problemas que os testes de integração acham que seriam perdidos pelos testes de unidade - o contrário não é verdade.
Voo 8/17
24

Sim, é possível ter muitos testes de unidade. Se você possui 100% de cobertura com testes de unidade e sem testes de integração, por exemplo, você tem um problema claro.

Alguns cenários:

  1. Você superdimensiona seus testes para uma implementação específica. Então você deve jogar fora os testes de unidade quando refatorar, para não dizer quando alterar a implementação (um ponto problemático muito frequente ao executar otimizações de desempenho).

    Um bom equilíbrio entre testes de unidade e testes de integração reduz esse problema sem perder uma cobertura significativa.

  2. Você pode ter uma cobertura razoável para cada confirmação com 20% dos testes que você possui, deixando os 80% restantes para integração ou pelo menos passados ​​testes separados; os principais efeitos negativos que você vê neste cenário são mudanças lentas, pois você precisa esperar muito tempo para que os testes sejam executados.

  3. Você modifica muito o código para permitir que você o teste; por exemplo, eu vi muitos abusos da IoC em componentes que nunca precisam ser modificados ou, pelo menos, é caro e de baixa prioridade generalizá-los, mas as pessoas investem muito tempo em generalizá-las e refatorá-las para permitir testes de unidade .

Concordo particularmente com a sugestão de obter 50% de cobertura em 100% dos arquivos, em vez de 100% de cobertura em 50% dos arquivos; concentre seus esforços iniciais nos casos positivos mais comuns e nos casos negativos mais perigosos, não invista muito no tratamento de erros e caminhos incomuns, não porque eles não sejam importantes, mas porque você tem um tempo limitado e um universo infinito de testes, então você precisa priorizar em qualquer caso.

Bruno Guardia
fonte
2
O que não é um problema com os testes de unidade, mas com a organização por ter suas prioridades erradas, exigindo um número específico para a cobertura de testes de unidade sem gastar os recursos para criar e executar testes adequados em outros níveis.
Jwenting
2
Concordo plenamente no número 3 e também o estenderia à passagem manual de instâncias de classes de nível inferior para classes de nível superior. Se algo de alto nível depende de algo de baixo nível para fazer algo, tudo bem. Se esconder os detalhes disso dos chamadores, eu chamaria isso de bom design. Mas se você fizer parte de baixo nível da interface de alto nível e fazer com que os chamadores passem, porque isso torna seus testes bonitos, agora a cauda está abanando o cachorro. (Se low-level-coisa é reutilizado em um monte de lugares, e muda muito, isso muda as coisas Na minha experiência que não foi típico..)
johncip
Eu amo sua descrição @johncip, definitivamente, que é um exemplo frequente de como uma classe agradável fica horrível, adicionando um monte de parâmetros necessários desnecessários para o construtor ...
de Bruno Guardia
19

Lembre-se de que cada teste tem um custo e um benefício. Os inconvenientes incluem:

  • um teste deve ser escrito;
  • um teste leva (normalmente uma quantidade muito pequena de) tempo para ser executado;
  • um teste deve ser mantido com o código - os testes devem mudar quando as APIs que estão testando mudam;
  • pode ser necessário alterar seu design para escrever um teste (embora essas alterações sejam geralmente para melhor).

Se os custos superam os benefícios, é melhor um teste não ser escrito. Por exemplo, se a funcionalidade é difícil de testar, a API muda com frequência, a correção é relativamente sem importância e a chance de o teste encontrar um defeito é baixa, é melhor você não escrevê-lo.

Quanto à sua proporção específica de testes para código, se o código for suficientemente denso da lógica, essa proporção poderá ser garantida. No entanto, provavelmente não vale a pena manter uma proporção tão alta em um aplicativo típico.

Segredo de Salomão
fonte
12

Sim, existem muitos testes de unidade.

Enquanto o teste é bom, todos os testes de unidade são:

  • Uma carga potencial de manutenção fortemente acoplada à API

  • Tempo que poderia ser gasto em outra coisa

  • Uma fatia de tempo no conjunto de testes unitários
  • Pode não estar agregando valor real porque, na verdade, é uma duplicata de algum outro teste com chance minúscula de que outro teste seja aprovado e esse teste falhará.

É aconselhável procurar 100% de cobertura de código, mas isso longe de significar um conjunto de testes, cada um dos quais fornece independentemente 100% de cobertura de código em algum ponto de entrada especificado (função / método / chamada etc.).

Embora dado o quão difícil seja possível obter uma boa cobertura e eliminar os erros, é provável que exista algo como "os testes unitários errados" e "muitos testes unitários".

Pragmática para a maioria dos códigos indica:

  1. Certifique-se de ter 100% de cobertura dos pontos de entrada (tudo é testado de alguma forma) e procure estar perto de 100% de cobertura de código dos caminhos de 'não erros'.

  2. Teste quaisquer valores ou tamanhos mínimos / máximos relevantes

  3. Teste qualquer coisa que você pense ser um caso especial engraçado, particularmente valores "ímpares".

  4. Quando você encontrar um bug, adicione um teste de unidade que o tenha revelado e pense se algum caso semelhante deve ser adicionado.

Para algoritmos mais complexos, considere também:

  1. Fazendo alguns testes em massa de mais casos.
  2. Comparando o resultado com uma implementação de 'força bruta' e verificando os invariantes.
  3. Usando algum método de produção de casos de teste aleatórios e verificação de força bruta e pós-condições, incluindo invariantes.

Por exemplo, verifique um algoritmo de classificação com alguma entrada aleatória e a validação dos dados é classificada no final, varrendo-o.

Eu diria que seu líder técnico está propondo testes de 'mínima bunda'. Estou oferecendo 'testes de qualidade de maior valor' e existe um espectro entre eles.

Talvez o seu veterano saiba que o componente que você está construindo será incorporado em uma peça maior e a unidade será testada mais detalhadamente quando integrada.

A principal lição é adicionar testes quando forem encontrados erros. O que me leva a minha melhor lição sobre o desenvolvimento de testes de unidade:

Concentre-se nas unidades e não nas sub-unidades. Se você estiver construindo uma unidade a partir de subunidades, escreva testes muito básicos para as subunidades até que sejam plausíveis e obtenha uma melhor cobertura testando as subunidades por meio de suas unidades de controle.

Portanto, se você estiver escrevendo um compilador e precisar escrever uma tabela de símbolos (digamos). Coloque a tabela de símbolos em funcionamento com um teste básico e trabalhe (digamos) no analisador de declaração que preenche a tabela. Adicione mais testes à unidade 'autônoma' da tabela de símbolos se encontrar erros nela. Caso contrário, aumente a cobertura por testes de unidade no analisador de declaração e posteriormente em todo o compilador.

Isso obtém o melhor retorno possível (um teste do todo está testando vários componentes) e deixa mais capacidade de reprojetar e aperfeiçoar, porque apenas a interface 'externa' é usada em testes que tendem a ser mais estáveis.

Juntamente com as pré-condições de teste do código de depuração, as pós-condições, incluindo invariantes em todos os níveis, você obtém a cobertura máxima do teste com a implementação mínima do teste.

Persixty
fonte
4
Eu não diria que 100% de cobertura é pragmática. 100% de cobertura é um padrão extremamente alto.
Bryan Oakley
Infelizmente, mesmo o método aleatório pode perder erros. Não há substituto para as provas, mesmo que informais.
Frank Hileman
@BryanOakley Point tomado. Isso é um exagero. Mas é mais importante chegar perto do que as pessoas dão crédito. "Eu testei o caminho fácil, está tudo bem" sempre causará problemas mais tarde.
Persixty
@FrankHileman A pergunta não era "O teste de unidade é um bom substituto para o design cuidadoso de software, lógica estática de verificação e algoritmos de comprovação", então a resposta é 'não'. Nenhum dos métodos produzirá software de alta qualidade por conta própria.
Persixty
3

Em primeiro lugar, não é necessariamente um problema ter mais linhas de teste do que código de produção. O código de teste é (ou deveria ser) linear e fácil de compreender - sua complexidade necessária é muito, muito baixa, independentemente de o código de produção ser ou não. Se a complexidade dos testes começar a se aproximar da do código de produção, é provável que você tenha um problema.

Sim, é possível ter muitos testes de unidade - um simples experimento mental mostra que você pode continuar adicionando testes que não fornecem valor adicional e que todos esses testes adicionados podem inibir pelo menos algumas refatorações.

O conselho para testar apenas os casos mais comuns é falho, na minha opinião. Eles podem atuar como testes de fumaça para economizar tempo de teste do sistema, mas os testes realmente valiosos capturam casos difíceis de exercitar em todo o sistema. Por exemplo, a injeção de erro controlada de falhas de alocação de memória pode ser usada para exercer caminhos de recuperação que, de outra forma, poderiam ser de qualidade completamente desconhecida. Ou passe zero como um valor que você sabe que será usado como um divisor (ou um número negativo com raiz quadrada) e verifique se você não recebe uma exceção não tratada.

Os próximos testes mais valiosos são aqueles que exercitam limites ou pontos extremos. Por exemplo, uma função que aceita meses (com base em 1) do ano deve ser testada com 0, 1, 12 e 13, para que você saiba que as transições válido-inválidas estão no lugar certo. É um teste excessivo também usar 2..11 para esses testes.

Você está em uma posição difícil, pois precisa escrever testes para o código existente. É mais fácil identificar os casos extremos à medida que você está escrevendo (ou prestes a escrever) o código.

Toby Speight
fonte
3

Minha compreensão do teste de unidade era testar cada método da classe para garantir que todos os métodos funcionassem conforme o esperado.

Esse entendimento está errado.

Os testes de unidade verificam o comportamento da unidade em teste .

Nesse sentido, uma unidade não é necessariamente "um método em uma classe". Gosto da definição de uma unidade de Roy Osherove em The Art of Unit Testing :

Uma unidade é todo o código de produção que tem o mesmo motivo para mudar.

Com base nisso, um teste de unidade deve verificar todo comportamento desejado do seu código. Onde o "desejo" é mais ou menos retirado dos requisitos.


No entanto, na solicitação de recebimento, meu líder técnico observou que eu deveria me concentrar em testes de nível superior.

Ele está certo, mas de uma maneira diferente do que ele pensa.

Pela sua pergunta, entendo que você é o "testador dedicado" nesse projeto.

O grande mal-entendido é que ele espera que você escreva testes de unidade (em contraste com "teste usando uma estrutura de teste de unidade"). Escrever testes ynit é de responsabilidade dos desenvolvedores , não dos testadores (em um mundo ideal, eu sei ...). Por outro lado, você marcou essa pergunta com TDD, o que implica exatamente isso.

Seu trabalho como testador é escrever (ou executar manualmente) módulos e / ou testes de aplicativos. E esse tipo de teste deve verificar principalmente se todas as unidades funcionam juntas sem problemas. Isso significa que você deve selecionar seus casos de teste para que cada unidade seja executada pelo menos uma vez . E essa verificação é que é executado. O resultado real é menos importante, pois está sujeito a alterações com requisitos futuros.

Para enfatizar a analogia do automóvel de despejo mais uma vez: Quantos testes são feitos com um carro no final da linha de montagem? Exatamente um: ele deve dirigir até o estacionamento sozinho ...

O ponto aqui é:

Precisamos estar cientes dessa diferença entre "testes de unidade" e "teste automatizado usando uma estrutura de teste de unidade".


Para mim, 100% de cobertura de teste de unidade é uma meta elevada, mas mesmo que atingíssemos apenas 50%, saberíamos que 100% desses 50% estavam cobertos.

Os testes de unidade são uma rede de segurança. Eles dão a você a confiança de refatorar seu código para reduzir a dívida técnica ou adicionar um novo comportamento sem medo de quebrar o comportamento já implementado.

Você não precisa de 100% de cobertura de código.

Mas você precisa de 100% de cobertura comportamental. (Sim, a cobertura do código e a cobertura do comportamento se correlacionam de alguma forma, mas não são idênticas por isso.)

Se você tiver menos de 100% de cobertura de comportamento, uma execução bem-sucedida do seu conjunto de testes não significa nada, pois você pode ter alterado um pouco do comportamento não testado. E você será notado pelo seu cliente no dia seguinte ao lançamento da sua versão online ...


Conclusão

Poucos testes são melhores que nenhum teste. Sem dúvida!

Mas não existe tal coisa como ter muitos testes de unidade.

Isso ocorre porque cada teste de unidade verifica uma única expectativa sobre o comportamento dos códigos . E você não pode escrever mais testes de unidade do que as expectativas em seu código. E um furo no seu cinto de segurança é a chance de uma alteração indesejada prejudicar o sistema de produção.

Timothy Truckle
fonte
2

Absolutamente sim. Eu costumava ser um SDET para uma grande empresa de software. Nossa pequena equipe teve que manter o código de teste que costumava ser tratado por uma equipe muito maior. Além disso, nosso produto possuía algumas dependências que estavam constantemente introduzindo alterações significativas, o que significa manutenção de teste constante para nós. Como não tínhamos a opção de aumentar o tamanho da equipe, tivemos que jogar fora milhares dos testes menos valiosos quando eles falharam. Caso contrário, nunca conseguiríamos acompanhar os defeitos.

Antes de descartar isso como um mero problema de gerenciamento, considere que muitos projetos no mundo real sofrem com redução de pessoal à medida que se aproximam do status de legado. Às vezes, isso começa a acontecer logo após o primeiro lançamento.

mrog
fonte
4
"Além disso, nosso produto tinha algumas dependências que estavam constantemente introduzindo mudanças significativas, o que significa manutenção de teste constante para nós". - Esses testes que você diz exigem som de manutenção como os valiosos se suas dependências quebrarem constantemente.
CodeMonkey 4/17/17
2
Isso não é um problema com os testes, mas com a organização.
Jwenting
2
@CodeMonkey As dependências não quebraram. Eles estavam sendo atualizados de maneiras que exigiam alterações em nosso produto. Sim, os testes foram valiosos, mas não tão valiosos quanto os outros. Os testes automatizados são mais valiosos quando o teste manual equivalente é difícil.
Mr #
2
@jwenting Sim, é um problema organizacional, não um problema de código. Mas isso não muda o fato de haver muitos testes. Um teste que não pode ser investigado é inútil, independentemente da causa.
Mr #
O que é um "SDET"?
Peter Mortensen
1

Ter mais linhas de código de teste que código de produto não é necessariamente um problema, supondo que você esteja refatorando seu código de teste para eliminar a copiar e colar.

O problema é ter testes que são espelhos de sua implementação, sem significado comercial - por exemplo, testes carregados com zombarias e stubs e afirmar apenas que um método chama outro método.

Uma ótima citação no artigo "por que a maioria dos testes de unidade é desperdício" é que os testes de unidade devem ter um "oráculo amplo, formal e independente de correção, e ... valor comercial atribuível"

wrschneider
fonte
0

Uma coisa que não vi mencionada é que seus testes precisam ser rápidos e fáceis para qualquer desenvolvedor executar a qualquer momento.

Você não precisa fazer check-in no controle de origem e aguardar uma hora ou mais (dependendo do tamanho da sua base de código) antes que os testes sejam concluídos para verificar se sua alteração quebrou algo - você pode fazer isso em sua própria máquina antes de fazer o check-in no controle de origem (ou pelo menos antes de enviar suas alterações). Idealmente, você poderá executar seus testes com um único script ou botão.

E quando você executa esses testes localmente, deseja que eles sejam executados rapidamente - na ordem de segundos. Mais devagar, e você será tentado a não executá-los o suficiente ou de maneira alguma.

Portanto, ter tantos testes que executá-los todos leva minutos ou ter alguns testes excessivamente complexos pode ser um problema.

mmathis
fonte