Se eu tiver algum código que tenha 80% de cobertura de teste (todos os testes passam), é justo dizer que é de qualidade superior ao código sem cobertura de teste?
Ou é justo dizer que é mais sustentável?
Se eu tiver algum código que tenha 80% de cobertura de teste (todos os testes passam), é justo dizer que é de qualidade superior ao código sem cobertura de teste?
Ou é justo dizer que é mais sustentável?
Respostas:
Em sentido estrito, não é justo fazer reivindicações até que a qualidade do conjunto de testes seja estabelecida. A aprovação em 100% dos testes não é significativa se a maioria dos testes for trivial ou repetitiva entre si.
A questão é: Na história do projeto, algum desses testes descobriu bugs? O objetivo de um teste é encontrar erros. E se não o fizeram, falharam como testes. Em vez de melhorar a qualidade do código, eles podem estar apenas fornecendo uma falsa sensação de segurança.
Para aprimorar seus projetos de teste, você pode usar (1) técnicas de caixa branca, (2) técnicas de caixa preta e (3) teste de mutação.
(1) Aqui estão algumas boas técnicas de caixa branca para aplicar aos seus projetos de teste. Um teste de caixa branca é construído com código-fonte específico em mente. Um aspecto importante do teste da caixa branca é a cobertura do código:
if
ou while
), você tem um teste que o força a ser verdadeiro e outro que o força a ser falso? [Cobertura de decisão]&&
) ou disjunção (usos ||
), cada subexpressão tem um teste em que é verdadeiro / falso? [Cobertura da condição]break
um de um loop é coberto?(2) As técnicas de caixa preta são usadas quando os requisitos estão disponíveis, mas o código em si não é. Isso pode levar a testes de alta qualidade:
(3) Por fim, suponha que você já tenha muitos testes agradáveis para cobertura de caixa branca e técnicas aplicadas de caixa preta. O que mais você pode fazer? É hora de testar seus testes . Uma técnica que você pode usar é o Teste de Mutação.
Sob teste de mutação, você faz uma modificação em (uma cópia) do seu programa, na esperança de criar um bug. Uma mutação pode ser:
Alterar uma referência de uma variável para outra variável; Inserir a função abs (); Alterar menor que para maior que; Excluir uma declaração; Substitua uma variável por uma constante; Excluir um método de substituição; Exclua uma referência a um super método; Alterar ordem dos argumentos
Crie várias dúzias de mutantes, em vários locais do seu programa [o programa ainda precisará ser compilado para testar]. Se seus testes não encontrarem esses erros, agora você precisará escrever um teste que possa encontrar o erro na versão mutada do seu programa. Depois que um teste encontra o bug, você mata o mutante e pode tentar outro.
Adendo : Esqueci de mencionar este efeito: os bugs tendem a se agrupar . O que isso significa é que quanto mais erros você encontrar em um módulo, maior a probabilidade de encontrar mais erros. Portanto, se você tem um teste que falha (ou seja, o teste é bem-sucedido, já que o objetivo é encontrar erros), não apenas você deve corrigi-lo, mas também deve escrever mais testes para o módulo, usando o comando técnicas acima.
Enquanto você encontrar bugs a uma taxa constante, os esforços de teste devem continuar. Somente quando houver um declínio na taxa de novos bugs encontrados, você deve ter certeza de que fez bons esforços de teste para essa fase de desenvolvimento.
Por uma definição, é mais sustentável, já que qualquer mudança de quebra é mais provável de ser detectada pelos testes.
No entanto, o fato de o código passar nos testes de unidade não significa que seja intrinsecamente de maior qualidade. O código ainda pode estar mal formatado com comentários irrelevantes e estruturas de dados inadequadas, mas ainda pode passar nos testes.
Eu sei qual código eu preferiria manter e estender.
Código com absolutamente nenhum teste pode ser de altíssima qualidade, legível, bonito e eficiente (ou total de lixo), portanto, não é justo dizer que o código com 80% de cobertura de teste é de qualidade superior ao código sem cobertura de teste.
Pode ser justo dizer que o código de 80% coberto com bons testes é provavelmente de qualidade aceitável e provavelmente relativamente de manutenção. Mas isso garante pouco, na verdade.
Eu chamaria isso de mais refatorável. A refatoração fica extremamente fácil se o código for coberto com muitos testes.
Seria justo chamá-lo de mais sustentável.
Eu concordaria sobre a parte de manutenção. Michael Feathers postou recentemente um vídeo de uma excelente palestra chamada " A profunda sinergia entre testabilidade e bom design ", na qual ele discute esse tópico. Na palestra, ele diz que o relacionamento é uma maneira, isto é, código bem projetado é testável, mas código testável não é necessariamente bem projetado.
Vale a pena notar que o streaming de vídeo não é ótimo no vídeo; portanto, pode valer a pena fazer o download se você quiser assistir na íntegra.
Eu já me faço essa pergunta há algum tempo em relação à "cobertura da condição". Então, que tal esta página em atollic.com "Por que a análise de cobertura de código?"
Mais tecnicamente, a análise de cobertura de código encontra áreas no seu programa que não são cobertas pelos seus casos de teste, permitindo que você crie testes adicionais que cobrem partes não testadas do seu programa. Portanto, é importante entender que a cobertura do código ajuda a entender a qualidade dos procedimentos de teste, não a qualidade do código em si .
Isso parece ser bastante relevante aqui. Se você tem um conjunto de casos de teste que consegue atingir um certo nível de cobertura (código ou não), é bem provável que esteja invocando o código em teste com um conjunto bastante exaustivo de valores de entrada! Isso não informa muito sobre o código em teste (a menos que o código exploda ou gere falhas detectáveis), mas oferece confiança no conjunto de casos de teste .
Em uma interessante mudança de visão do Necker Cube , o código de teste agora está sendo testado pelo código em teste!
Existem várias maneiras de garantir que um programa faça o que você pretende e de garantir que as modificações não produzam efeitos indesejados.
Teste é um. Evitar a mutação de dados é outro. Então é um sistema de tipos. Ou verificação formal.
Portanto, embora eu concorde que o teste geralmente é uma coisa boa, uma determinada porcentagem do teste pode não significar muito. Prefiro confiar em algo escrito em Haskell sem testes do que em uma biblioteca PHP bem testada