Por que os testes de unidade não são vistos como ruins?

88

Em algumas organizações, aparentemente, parte do processo de lançamento de software é usar o teste de unidade, mas a qualquer momento todos os testes de unidade devem passar. Por exemplo, pode haver alguma tela que mostre todos os testes de unidade passando em verde - o que é suposto ser bom.

Pessoalmente, acho que não é assim que deve ser pelas seguintes razões:

  1. Ele promove a ideia de que o código deve ser perfeito e não deve haver bugs - o que no mundo real é certamente impossível para um programa de qualquer tamanho.

  2. É um desincentivo pensar em testes unitários que falharão. Ou, certamente, apresentar testes de unidade que seriam complicados de corrigir.

  3. Se, a qualquer momento, todos os testes de unidade passarem, então não há uma grande imagem do estado do software a qualquer momento. Não há roteiro / objetivo.

  4. Detecta testes de unidade de escrita antecipadamente - antes da implementação.

Eu até sugeriria que mesmo liberar software com testes de unidade com falha não é necessário. Pelo menos então você sabe que algum aspecto do software tem limitações.

Estou sentindo falta de algo aqui? Por que as organizações esperam que todos os testes de unidade sejam aprovados? Isso não é viver em um mundo de sonhos? E isso não impede uma compreensão real do código?

    
por user619818 22.05.2018 / 12:32
fonte

17 respostas

263

Esta pergunta contém vários conceitos errôneos da IMHO, mas o principal que eu gostaria de focar é que ela não diferencia entre agências locais de desenvolvimento, tronco, estágios ou agências de lançamento.

Em uma ramificação de desenvolvimento local, é provável que tenha alguns testes de unidade com falha a qualquer momento. No porta-malas, só é aceitável em algum grau, mas já é um strong indicador para corrigir as coisas o mais rápido possível. Observe que os testes de unidade com falha no tronco podem perturbar o restante da equipe, pois exigem que todos verifiquem se a última alteração dele não causou a falha.

Em uma ramificação de teste ou de liberação, os testes com falha são "alerta vermelho", mostrando que algo foi completamente errado com algum changeset, quando foi mesclado do tronco para o ramo de release.

I would even suggest that even releasing software with failing unit tests is not necessary bad.

Liberar software com alguns erros conhecidos abaixo de determinada gravidade não é necessariamente ruim. No entanto, essas falhas conhecidas não devem causar um teste de unidade com falha. Caso contrário, após cada teste de unidade, será necessário examinar os 20 testes de unidade com falha e verificar um por um se a falha foi aceitável ou não. Isso fica pesado, propenso a erros e descarta uma grande parte do aspecto de automação dos testes de unidade.

Se você realmente tiver testes para bugs conhecidos e aceitáveis, use o recurso de desabilitar / ignorar da ferramenta de testes de unidade (para que eles não sejam executados por padrão, apenas sob demanda). Além disso, adicione um tíquete de baixa prioridade ao rastreador de problemas, para que o problema não seja esquecido.

    
por 22.05.2018 / 13:48
fonte
227

... all unit tests passing in green - which is supposed to be good.

é bom. Não "deveria ser" sobre isso.

It promotes the idea that code should be perfect and no bugs should exist - which in the real world is surely impossible for a program of any size.

Não. Isso prova que você testou o código tão bem quanto possível até o momento. É totalmente possível que seus testes não cubram todos os casos. Se assim for, quaisquer erros eventualmente aparecerão em relatórios de erros e você escreverá [testes] para reproduzir os problemas e então corrigir o aplicativo para que os testes sejam aprovados.

It is a disincentive to think up unit tests that will fail.

Testes falhos ou negativos colocam limites firmes sobre o que seu aplicativo aceitará ou não. A maioria dos programas que conheço irá se opor a uma "data" de 30 de fevereiro. Além disso, os desenvolvedores, tipos criativos que somos, não querem quebrar "seus bebês". O foco resultante em casos de "caminho feliz" leva a aplicativos frágeis que quebram - frequentemente.

Para comparar a mentalidade do desenvolvedor e do testador:

  • Um desenvolvedor pára assim que o código faz o que eles querem.
  • Um testador pára quando não consegue mais quebrar o código.

Essas são perspectivas radicalmente diferentes e difíceis de serem reconciliadas por muitos desenvolvedores.

Or certainly come up with unit tests that would be tricky to fix.

Você não escreve testes para trabalhar sozinho. Você escreve testes para garantir que o seu código está fazendo o que é suposto fazer e, mais importante, que ele continua a fazer o que deve fazer após ter alterado o código implementação interna.

  • A depuração "prova" que o código faz o que você quer para hoje .
  • Testes "provam" que o código ainda faz o que você quer ao longo do tempo .

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

O único teste de "imagem" é um instantâneo de que o código "funciona" no momento em que foi testado. Como isso evolui depois disso é uma história diferente.

It deters writing unit tests up-front - before the implementation.

Isso é exatamente o que você deveria estar fazendo. Escreva um teste que falhe (porque o método que ele está testando ainda não foi implementado) e então escreva o código do método para fazer o método funcionar e, portanto, o teste de aprovação. Isso é basicamente o ponto crucial do Desenvolvimento Orientado a Testes.

I would even suggest that even releasing software with failing unit tests is not necessary bad. At least then you know that some aspect of the software has limitations.

Liberar código com testes quebrados significa que parte de sua funcionalidade não funciona mais como antes. Isso pode ser um ato deliberado porque você corrigiu um bug ou aprimorou um recurso (mas você deve ter alterado o teste primeiro para que ele falhe, então codifique a correção / aprimoramento, fazendo o teste funcionar no processo). Mais importante: somos todos humanos e cometemos erros. Se você quebrar o código, então você deve quebrar os testes e os testes quebrados devem definir os sinos de alarme tocando.

Isn't this living in a dream world?

Se alguma coisa, ele está vivendo no Real World , reconhecendo que os desenvolvedores não são nem oniscientes nem infalíveis, que nós fazemos cometer erros e que precisamos de um segurança net para nos pegar se e quando nós fizermos bagunçar!
Digite testes.

And doesn't it actually deter a real understanding of code?

Talvez. Você não precisa necessariamente entender a implementação de algo para escrever teste (isso faz parte do ponto deles). Os testes definem o comportamento e os limites do aplicativo e garantem que eles permaneçam os mesmos, a menos que você os altere deliberadamente.

    
por 22.05.2018 / 13:08
fonte
31

Why are unit tests failing seen as bad?

Eles não são - o desenvolvimento orientado a testes é baseado na noção de testes com falha. Testes de unidade com falha para impulsionar o desenvolvimento, testes de aceitação falhos para gerar uma história ...

O que você está perdendo é contexto ; onde os testes unitários podem falhar?

A resposta usual é que os testes de unidade só podem falhar em sandboxes particulares.

A noção básica é a seguinte: em um ambiente em que os testes com falha são compartilhados, é necessário um esforço extra para entender se uma alteração no código de produção introduziu um novo erro. A diferença entre zero e não zero é muito mais fácil de detectar e gerenciar do que a diferença entre N e não N.

Além disso, manter o código compartilhado limpo significa que os desenvolvedores podem permanecer na tarefa. Quando eu mesclar seu código, não preciso mudar os contextos do problema que estou sendo pago para resolver, para calibrar minha compreensão de quantos testes devem estar falhando. Se o código compartilhado estiver passando em todos os testes, qualquer falha que apareça quando eu mesclar minhas alterações deve fazer parte da interação entre meu código e a linha de base limpa existente.

Da mesma forma, durante o embarque, um novo desenvolvedor pode se tornar produtivo mais rapidamente, pois não precisa perder tempo descobrindo quais testes com falha são "aceitáveis".

Para ser mais preciso: a disciplina é que os testes que são executados durante a compilação devem passar.

Há, o melhor que posso dizer, nothing errado com testes com falhas que estão desativados .

Por exemplo, em um ambiente de "integração contínua", você estará compartilhando código em alta cadência. Integrar muitas vezes não significa necessariamente que suas alterações precisam ser liberadas. Há uma variedade de técnicas de implantação escuras que impedem que o tráfego seja liberado em seções do código até que estejam prontas.

Essas mesmas técnicas também podem ser usadas para desativar testes com falhas.

Um dos exercícios pelos quais passei em um comunicado estava lidando com o desenvolvimento de um produto com muitos testes fracassados. A resposta que tivemos foi simplesmente passar pela suíte, desabilitando os testes com falha e documentando cada um. Isso nos permitiu chegar rapidamente a um ponto em que todos os testes habilitados estavam passando, e o dono do gerenciamento / meta / proprietário de ouro podia ver quais negociações nós tínhamos feito para chegar a esse ponto e poder tomar decisões informadas sobre limpeza versus novo trabalho.

Resumindo: existem outras técnicas para rastrear o trabalho não realizado do que deixar um monte de testes com falha na suíte em execução.

    
por 22.05.2018 / 14:37
fonte
25

Há muitas ótimas respostas, mas eu gostaria de acrescentar outro ângulo que acredito ainda não estar bem coberto: o que exatamente é o ponto de ter testes.

Testes de unidade não estão lá para verificar se seu código está livre de erros.

Acho que esse é o principal equívoco. Se esse era o seu papel, você realmente esperaria ter testes fracassados em todo o lugar. Mas em vez disso,

Testes de unidade verificam se o seu código faz o que você acha que faz.

Em casos extremos, pode incluir a verificação de que os bugs conhecidos não são corrigidos. O objetivo é ter controle sobre sua base de código e evitar mudanças acidentais. Quando você faz uma mudança, está tudo bem e espera-se que você faça alguns testes - você está mudando o comportamento do código. O teste recém-quebrado agora é uma boa trilha do que você mudou. Verifique se todas as quebras estão de acordo com o que você quer da sua mudança. Se sim, apenas atualize os testes e continue. Se não - bem, o seu novo código é definitivamente defeituoso, volte e corrija antes de enviar!

Agora, todos os itens acima funcionam somente se todos os testes forem verdes, dando um resultado positivo muito strong: é exatamente assim que o código funciona. Testes vermelhos não têm essa propriedade. "Isto é o que este código não faz" raramente é uma informação útil.

Testes de aceitação podem ser o que você está procurando.

Existe o teste de aceitação. Você pode escrever um conjunto de testes que devem ser atendidos para chamar o próximo marco. Estes são ok para ser vermelho, porque é para isso que eles foram projetados. Mas eles são muito diferentes dos testes unitários e nem podem substituí-los.

    
por 22.05.2018 / 18:17
fonte
24

Eu o vejo como o equivalente de software da síndrome da janela quebrada .

Testes de trabalho me dizem que o código é de uma determinada qualidade e que os proprietários do código se preocupam com isso.

Quanto a quando você deve se preocupar com a qualidade, isso depende de qual branch / repositório do código-fonte você está trabalhando. O código de desenvolvimento pode muito bem ter testes quebrados indicando o trabalho em andamento (esperançosamente!).

Testes quebrados em uma filial / repositório de um sistema ativo devem definir imediatamente o toque dos sinos de alarme. Se os testes quebrados puderem continuar a falhar ou se estiverem marcados permanentemente como "ignorar" - espere que o número deles aumente com o tempo. Se estes não forem regularmente revisados, o precedente terá sido definido para que não haja mais testes quebrados.

Testes quebrados são vistos de maneira pejorativa em muitas lojas, a ponto de ter uma restrição se um código corrompido pode ser confirmado .

    
por 22.05.2018 / 14:54
fonte
11

Aqui está a falácia lógica subjacente:

If it is good when all tests pass, then it must be bad if any tests fail.

Com testes unitários, é IS bom quando todos os testes passam. É também bom quando um teste falha. Os dois não precisam estar em oposição.

Um teste com falha é um problema que foi detectado pelo seu conjunto de ferramentas antes de atingir um usuário. É uma oportunidade para corrigir um erro antes de ser publicado. E isso é bom.

    
por 22.05.2018 / 19:47
fonte
9

A resposta do Phill W é ótima. Eu não posso substituí-lo.

No entanto, quero me concentrar em outra parte que pode ter sido parte da confusão.

In some organisations, apparently, part of the software release process is to use unit testing, but at any point in time all unit tests must pass

"a qualquer momento" está exagerando o seu caso. O importante é que os testes de unidade passem após uma determinada alteração ter sido implementada, antes de você começar a implementar outra alteração.
É assim que você acompanha a mudança que causou o surgimento de um bug. Se os testes de unidade começaram a falhar após implementar a mudança 25, mas antes de implementar a mudança 26, então você sabe que a alteração 25 causou o erro.

Durante a implementação de uma mudança, é claro que os testes de unidade podem falhar; tat depende muito de quão grande é a mudança. Se estou desenvolvendo um recurso principal, que é mais do que apenas um pequeno ajuste, provavelmente vou interromper os testes por um tempo até terminar de implementar minha nova versão da lógica.

Isso pode criar conflitos quanto às regras da equipe. Eu realmente encontrei isso há algumas semanas:

  • Cada commit / push causa uma compilação. A compilação nunca deve falhar (se ocorrer algum teste ou qualquer teste falhar, o desenvolvedor comprometido será culpado).
  • Espera-se que cada desenvolvedor envie suas alterações (mesmo que incompletas) no final do dia, para que os líderes da equipe possam codificar a revisão pela manhã.
A regra

Qualquer um estaria bem. Mas as regras ambas não podem funcionar juntas. Se eu receber uma alteração importante que leve vários dias para ser concluída, não conseguiria aderir às duas regras ao mesmo tempo. A menos que eu comentasse as minhas alterações todos os dias e apenas as comesse sem comentários depois de tudo ter sido feito; que é apenas um trabalho sem sentido.

Neste cenário, a questão aqui não é que os testes unitários não tenham propósito; é que a empresa tem expectativas irrealistas . Seu conjunto de regras arbitrárias não cobre todos os casos, e a falha em aderir às regras é cegamente considerada falha do desenvolvedor, em vez de falha de regra (o que é, no meu caso).

    
por 22.05.2018 / 15:57
fonte
6

Se você não corrigir todos os testes de unidade, poderá entrar rapidamente no estado em que ninguém corrige nenhum teste quebrado.

  1. É incorreto, pois a passagem de testes de unidade não mostra que o código é perfeito

  2. É um desincentivo para criar código que seria difícil de testar também, o que é bom do ponto de vista do design

  3. A cobertura de código pode ajudar lá (embora não seja uma panacéia). Também testes unitários são apenas um aspecto do teste - você também quer testes de integração / aceitação.

por 22.05.2018 / 12:35
fonte
6

Para adicionar alguns pontos às já boas respostas ...

but at any point in time all unit tests must pass

Isso mostra uma falta de compreensão de um processo de lançamento. Uma falha de teste pode indicar um recurso planejado em TDD que ainda não está implementado; ou pode indicar um problema conhecido que tenha uma correção planejada para uma liberação futura; ou pode ser simplesmente algo em que a gerência decidiu que isso não é importante o suficiente para corrigir, porque é improvável que os clientes percebam. A principal coisa que todos compartilham é que a gerência fez um julgamento sobre o fracasso.

It promotes the idea that code should be perfect and no bugs should exist - which in the real world is surely impossible for a program of any size.

Outras respostas cobriram os limites do teste.

Eu não entendo porque você acha que a eliminação de bugs é um ponto negativo. Se você não quiser entregar o código que você verificou (com o melhor de sua capacidade), faça o que deveria, por que você está trabalhando em software?

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

Por que deve haver um roteiro?

Os testes unitários verificam inicialmente se a funcionalidade funciona, mas depois (como testes de regressão) verifica se você não quebrou inadvertidamente alguma coisa. Para todos os recursos com testes de unidade existentes, não há roteiro . Cada recurso é conhecido por funcionar (dentro dos limites do teste). Se esse código estiver concluído, não há roteiro porque não há necessidade de mais trabalho.

Como engenheiros profissionais, precisamos evitar a armadilha de chapeamento de ouro. Os amadores podem se dar ao luxo de perder tempo mexendo nas bordas com algo que funciona. Como profissionais, precisamos entregar um produto. Isso significa que temos algo funcionando, verificamos se está funcionando e passamos para o próximo trabalho.

    
por 22.05.2018 / 16:34
fonte
6

It promotes the idea that code should be perfect and no bugs should exist - which in the real world is surely impossible for a program of any size.

Não é verdade. Por que você acha que é impossível? aqui exemplo para programa que funciona:

public class MyProgram {
  public boolean alwaysTrue() {
    return true;
  }

  @Test
  public void testAlwaysTrue() {
    assert(alwaysTrue() == true);
  }
}

It is a disincentive to think up unit tests that will fail. Or certainly come up with unit tests that would be tricky to fix.

Nesse caso, pode não ser o teste unitário, mas o teste de integração, se for complicado

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

true, ele é chamado de teste unidade por um motivo, verifique uma pequena unidade de código.

It deters writing unit tests up-front - before the implementation.

Desenvolvedores irão impedir a escrita de quaisquer testes se eles não entenderem seus benefícios por sua natureza (a menos que eles tenham vindo do controle de qualidade)

    
por 22.05.2018 / 12:44
fonte
4

It promotes the idea that code should be perfect and no bugs should exist

Definitivamente não é. Promove a ideia de que seus testes não devem falhar, nada mais e nada menos. Supondo que ter testes (mesmo muitos deles) diz algo sobre "perfeito" ou "sem bugs" é uma falácia. Decidir quão rasa ou profunda seus testes devem ser é uma parte significativa da escrita de bons testes e a razão pela qual temos categorias distintas de testes (testes unitários, testes de integração, cenários no sentido pepino etc.). / p>

It is a disincentive to think up unit tests that will fail. Or certainly come up with unit tests that would be tricky to fix.

No desenvolvimento orientado por testes, é obrigatório que os testes de unidades todos apresentem falhas antes de começar a codificar. Chama-se "ciclo vermelho-verde" (ou "ciclo vermelho-verde-refatorador") por essa mesma razão.

  • Sem a falha do teste, você não sabe se o código é realmente testado pelo teste. Os dois podem não estar relacionados a todos.
  • Ao alterar o código para exatamente fazer o teste mudar de vermelho para verde, nada mais e nada menos, você pode ter certeza de que seu código faz o que deve fazer e não um muito mais (o que você talvez nunca precise).

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

Os testes são mais uma espécie de meta micro. No desenvolvimento orientado a testes, o programador escreverá primeiro um teste (singular) e, em seguida, terá um objetivo claro de implementar algum código; então o próximo teste, e assim por diante.

A função dos testes não é estar completa quando o código é escrito.

Quando feito corretamente, em uma linguagem e com uma biblioteca de testes bem adaptada a essa abordagem, isso pode realmente acelerar o desenvolvimento, já que as mensagens de erro (exceções / stacktraces) podem direcionar diretamente o desenvolvedor para onde ele precisa para executar o trabalho a seguir.

It deters writing unit tests up-front - before the implementation.

Eu não vejo como essa afirmação seria verdadeira. Escrever testes deveria idealmente ser uma parte da implementação.

Am I missing something here? Why do organisations expect all unit tests to pass?

Porque as organizações esperam que os testes tenham relevância para o código. Escrever testes que tenham êxito significa que você documentou alguma parte do seu aplicativo e comprovou que o aplicativo faz o que ele (o teste) diz. Nada mais e nada menos.

Além disso, uma parte muito grande de testes é "regressão". Você quer ser capaz de desenvolver ou refatorar o novo código com confiança. Ter uma grande quantidade de testes ecológicos permite que você faça isso.

Isso vai do nível organizacional ao psicológico. Um desenvolvedor que sabe que seus erros provavelmente serão capturados pelos testes será muito mais livre para encontrar soluções inteligentes e ousadas para os problemas que ele precisa resolver. Por outro lado, um desenvolvedor que não tem testes ficará, depois de algum tempo, paralisado (devido ao medo), porque ele nunca sabe se uma mudança que ele faz quebra o restante do aplicativo.

Isn't this living in a dream world?

Não. Trabalhar com um aplicativo orientado a testes é pura alegria - a menos que você não goste do conceito por qualquer motivo ("mais esforço" etc. etc.) que possamos discutir em outra pergunta.

And doesn't it actually deter a real understanding of code?

Absolutamente não, por que isso aconteceria?

Você encontra muitos projetos grandes de código aberto (para os quais o gerenciamento do "entendimento" e do know-how sobre o código é um tópico muito premente) que realmente usa os testes como a principal documentação do software, além de sendo testes, também fornecem exemplos reais, funcionais e sintaticamente corretos para usuários ou desenvolvedores do aplicativo / biblioteca. Isso geralmente funciona esplendidamente.

Obviamente, escrever testes ruins é ruim. Mas isso não tem nada a ver com a função dos testes em si.

    
por 23.05.2018 / 11:14
fonte
3

(dos meus comentários originais)

Há uma diferença entre a funcionalidade exigida e as metas futuras. Os testes são para funcionalidade necessária: são precisos, formais, executáveis e, se falharem, o software não funciona. Objetivos futuros podem não ser precisos ou formais, e muito menos executáveis, então é melhor deixá-los em linguagem natural, como em questão / rastreadores de bugs, documentação, comentários, etc.

Como exercício, tente substituir a frase "teste de unidade" na sua pergunta por "erro do compilador" (ou "erro de sintaxe", se não houver compilador). É óbvio que uma versão não deveria ter erros de compilador, já que seria inutilizável; no entanto, erros de compilador e erros de sintaxe são o estado normal das coisas na máquina de um desenvolvedor quando estão escrevendo código. Os erros só desaparecem quando terminam; e é exatamente quando o código deve ser enviado. Agora substitua "erro do compilador" neste parágrafo por "teste de unidade":)

    
por 23.05.2018 / 19:25
fonte
2

O objetivo dos testes automatizados é informar quando você tiver quebrado algo o mais cedo possível . O fluxo de trabalho é um pouco parecido com isto:

  1. Faça uma alteração
  2. Crie e teste sua alteração (idealmente automaticamente)
  3. Se os testes falharem, significa que você quebrou algo que funcionou anteriormente
  4. Se os testes forem aprovados, você deve ter certeza de que sua alteração não introduziu novas regressões (dependendo da cobertura do teste)

Se seus testes já estavam falhando, o passo 3 não funciona tão bem - os testes falharão, mas você não sabe se isso significa que você quebrou algo ou não, sem investigar. Talvez você possa contar o número de testes com falha, mas, em seguida, uma alteração pode corrigir um bug e quebrar outro, ou um teste pode começar a falhar por um motivo diferente. Isso significa que você precisa aguardar algum tempo antes de saber se algo foi quebrado até que todos os problemas tenham sido corrigidos ou até que cada teste com falha tenha sido investigado.

A capacidade de testes unitários para encontrar bugs recém-introduzidos o mais cedo possível é a coisa mais valiosa sobre o teste automatizado - quanto mais tempo um defeito não é descoberto, mais caro é consertar.

It promotes the idea that code should be perfect and no bugs should exist
It is a disincentive to think up unit tests that will fail

Testes para coisas que não funcionam não lhe dizem nada - escreva testes unitários para coisas que o faz funcionem, ou que você está prestes a consertar. Isso não significa que seu software está livre de defeitos, isso significa que nenhum dos defeitos que você escreveu anteriormente para testes de unidade voltou.

It deters writing unit tests up-front

Se funcionar para você, então escreva testes na frente, apenas não os registre no seu master / trunk até que eles passem.

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

Testes de unidade não são para definir um roteiro / meta, talvez usar um backlog para isso? Se todos os seus testes passarem, então a "grande figura" é que o seu software não está quebrado (se a sua cobertura de teste for boa). Bem feito!

    
por 23.05.2018 / 22:30
fonte
2

As respostas existentes são certamente boas, mas eu não vi ninguém abordar esse equívoco fundamental na pergunta:

at any point in time all unit tests must pass

Não. Certamente, isso não será verdade. Enquanto desenvolvo software, o NCrunch é mais comumente marrom (falha de compilação) ou vermelho (falha de teste).

Onde o NCrunch precisa ser verde (todos os testes passando) é quando estou pronto para enviar uma confirmação para o servidor de controle de origem, porque nesse momento outros podem depender do meu código. / p>

Isso também alimenta o tópico da criação de novos testes: os testes devem confirmar a lógica e o comportamento do código. Condições de limite, condições de falha, etc. Quando escrevo novos testes, tento identificar esses "pontos quentes" no código.

Testes de unidade documentam como eu espero que meu código seja chamado - pré-condições, saídas esperadas, etc.

Se um teste falhar após uma alteração, preciso decidir se o código ou o teste está com erro.

Como uma observação, os testes unitários às vezes andam de mãos dadas com o Test Driven Development. Um dos princípios do TDD é que os testes quebrados são seus indicadores. Quando um teste falha, você precisa corrigir o código para que o teste seja aprovado. Aqui está um exemplo concreto do início desta semana:

Background : eu escrevi e agora suporto uma biblioteca usada por nossos desenvolvedores que é usada para validar as consultas do Oracle. Tínhamos testes que afirmavam que a consulta correspondia a algum valor esperado, o que tornava o caso importante (não está no Oracle) e aprovava alegremente as consultas inválidas, desde que correspondessem completamente ao valor esperado.

Em vez disso, minha biblioteca analisa a consulta usando o Antlr e uma sintaxe do Oracle 12c e, em seguida, envolve várias asserções na própria árvore de sintaxe. Coisas como, é válido (nenhum erro de análise foi gerado), todos os seus parâmetros são atendidos pela coleção de parâmetros, todas as colunas esperadas lidas pelo leitor de dados estão presentes na consulta, etc. Todos esses são itens que passaram por produção em vários momentos.

Um dos meus colegas engenheiros me enviou uma consulta na segunda-feira que falhou (ou melhor, teve sucesso quando deveria ter falhado) no fim de semana. Minha biblioteca disse que a sintaxe estava boa, mas explodiu quando o servidor tentou executá-la. E quando ele olhou para a consulta, ficou óbvio porque:

UPDATE my_table(
SET column_1 = 'MyValue'
WHERE id_column = 123;

Eu carreguei o projeto e adicionei um teste de unidade que afirmava que essa consulta não deveria ser válida. Obviamente, o teste falhou.

Em seguida, depurei o teste com falha, percorri o código onde esperava que ele emitisse a exceção e descobri que o Antlr estava gerando um erro no paren aberto, mas não de uma maneira o código anterior estava esperando. Eu modifiquei o código, verifiquei que o teste agora estava verde (passando) e que nenhum outro tinha quebrado no processo, cometido e empurrado.

Isso demorou cerca de 20 minutos e, no processo, eu realmente melhorei a biblioteca de forma significativa, pois ela agora dava suporte a toda uma gama de erros que anteriormente ela ignorava. Se eu não tivesse testes de unidade para a biblioteca, pesquisar e corrigir o problema poderia levar horas.

    
por 24.05.2018 / 16:20
fonte
0

Um ponto que não penso nas respostas anteriores é que há uma diferença entre testes internos e testes externos (e acho que muitos projetos não são cuidadosos o suficiente para distinguir os dois). Um teste interno testa que algum componente interno está funcionando da maneira que deveria; Um teste externo mostra que o sistema como um todo está funcionando como deveria. É bem possível, é claro, ter falhas em componentes que não resultem em uma falha do sistema (talvez haja um recurso do componente que o sistema não usa ou, talvez, o sistema se recupere de uma falha do sistema). componente). Uma falha de componente que não resulta em uma falha do sistema não deve impedi-lo de liberar.

Eu vi projetos que estão paralisados por ter muitos testes de componentes internos. Toda vez que você tenta implementar uma melhoria de desempenho, você quebra dezenas de testes, porque está mudando o comportamento dos componentes sem realmente alterar o comportamento visível externamente do sistema. Isso leva a uma falta de agilidade no projeto como um todo. Acredito que o investimento em testes de sistemas externos geralmente tem um retorno muito melhor do que o investimento em testes de componentes internos, especialmente quando se fala em componentes de nível muito baixo.

Quando você sugere que testes unitários fracassados realmente não importam, pergunto-me se isso é o que você tem em mente. Talvez você deva estar avaliando o valor dos testes de unidade e descartando aqueles que causam mais problemas do que valem, enquanto se concentra mais em testes que verificam o comportamento visível externamente do aplicativo.

    
por 24.05.2018 / 15:43
fonte
0

"mas a qualquer momento todos os testes de unidade devem passar"

Se essa é a atitude da sua empresa, isso é um problema. Em um determinado momento, ou seja, quando declaramos que o código está pronto para passar para o próximo ambiente, todos os testes de unidade devem passar. Mas durante o desenvolvimento, devemos esperar rotineiramente que muitos testes unitários falhem.

Nenhuma pessoa razoável espera que um programador melhore seu trabalho na primeira tentativa. O que fazemos razoavelmente esperar é que ele continue trabalhando até que não haja problemas conhecidos.

"É um desestímulo para pensar em testes unitários que irão falhar. Ou certamente criar testes unitários que seriam difíceis de consertar." Se alguém em sua organização acha que não deve mencionar um possível teste porque pode falhar e causar mais trabalho para consertá-lo, essa pessoa é totalmente desqualificada para seu trabalho. Essa é uma atitude desastrosa. Você quer um médico que diga: "Quando eu estou fazendo uma cirurgia, eu deliberadamente não verifico se os pontos estão certos, porque se eu perceber que eles não estão, eu vou ter que voltar e refazê-los e isso vai diminuir a conclusão da operação "?

Se a equipe é hostil a programadores que identificam erros antes que o código vá para a produção, você tem um problema real com a atitude dessa equipe. Se a gerência castiga os programadores que identificam erros que retardam a entrega, as probabilidades são de que sua empresa esteja indo à falência.

Sim, é certamente verdade que às vezes pessoas racionais dizem: "Estamos nos aproximando do prazo, este é um problema trivial e não vale a pena dedicar os recursos agora que seria necessário para consertá-lo". Mas você não pode tomar essa decisão racionalmente se não souber. Examinar friamente uma lista de erros e atribuir prioridades e cronogramas para corrigi-los é racional. Deliberadamente fazendo-se ignorante dos problemas para que você não tenha que tomar essa decisão é tolice. Você acha que o cliente não vai descobrir só porque você não queria saber?

    
por 28.05.2018 / 01:17
fonte
-7

Este é um exemplo específico de viés de confirmação , em que as pessoas tendem a buscar informações que confirmem suas crenças existentes.

Um exemplo famoso disso está no jogo do 2,4,6.

  • Eu tenho uma regra na minha cabeça de que qualquer série de três números passará ou falhará,
  • 2,4,6 é um passe
  • você pode listar conjuntos de três números e eu lhe direi se eles passarem ou falharem.

A maioria das pessoas escolhe uma regra, digamos que "o intervalo entre o primeiro e o segundo números é o mesmo que o intervalo entre o segundo e o terceiro".

Eles testarão alguns números:

  • 4, 8, 12? Passar
  • 20, 40, 60? Passar
  • 2, 1004, 2006? Passar

Eles dizem: "Sim, toda observação confirma minha hipótese, deve ser verdade". E anuncie sua regra para a pessoa que está dando o enigma.

Mas eles nunca receberam uma única falha em qualquer conjunto de três números. A regra poderia ter sido "os três números precisam ser números" para todas as informações que eles realmente têm.

A regra é apenas que os números estão em ordem crescente. Normalmente, as pessoas só conseguem corrigir esse enigma se testarem o fracasso. A maioria das pessoas erra, escolhendo uma regra mais específica e apenas testando números que atendam a essa regra específica.

Por que as pessoas se apaixonam pelo viés de confirmação, e podem ver testes de unidade fracassarem como evidência de um problema, há muitos psicólogos que podem explicar melhor o viés de confirmação do que eu, basicamente se trata de pessoas que não gostam de estar erradas e que lutam genuinamente tentar provar que estão errados.

    
por 23.05.2018 / 06:17
fonte