Como você verifica se o código foi coberto automaticamente?


9

Estou no processo de configurar um servidor Bamboo para alguns novos projetos para enviar para TDD em um fluxo de trabalho de CI / CD. Certamente, o teste de unidade é ótimo, mas apenas como o registro existente.

Agora, isso pode ser melhor em um gancho de pré-recebimento do GIT em determinadas ramificações (ou seja: ramificações de desenvolvimento e liberação principal), mas como a cobertura do código deve ser imposta, se houver. Fico feliz em confiar nos committers para garantir que o código seja coberto, mas como essas coisas são mantidas sem nenhum desvio além da diligência e consistência?

Em resumo, gostaria de ver como outras pessoas aplicam a cobertura de teste como um processo automático durante os estágios de confirmação ou criação.

Respostas:


17

Você não deve impor a cobertura do código automaticamente.

É como impor o máximo de linhas de código por método: concordado, a maioria dos métodos deve ser menor que, digamos, 20 LOC, mas há casos válidos em que os métodos seriam mais longos que isso.

Da mesma forma, segmentar uma determinada porcentagem de cobertura de código por classe pode levar a conseqüências indesejadas. Por exemplo:

  • Classes de código padrão ou classes criadas por geradores de código podem não ser testadas. Forçar os desenvolvedores a testá-los não terá nenhum benefício e terá um custo substancial em termos de tempo gasto com isso.

  • O código simples que manipula partes não importantes do aplicativo não precisa necessariamente ser testado.

  • Em alguns idiomas, algum código não pode ser testado. Eu tive esse caso em C # com métodos anônimos em uma biblioteca onde eu realmente queria ter 100% de cobertura de código. Esses casos podem ser desmoralizantes para os desenvolvedores.

Mais importante, a cobertura do código deve ser proporcional a dois aspectos do código: quão crítico e quão complicado é :

  • Um pedaço de código com uma lógica complicada, que faz parte do principal recurso de um aplicativo, seria melhor testado cuidadosamente, porque falhas ou regressões podem ter consequências importantes.

  • Um código simples que lida com um recurso que ninguém usa pode ter testes básicos que abrangem apenas casos básicos.

Obviamente, você ainda pode usar a cobertura de código como uma medida , especialmente para comparar como equipes diferentes obtêm cobertura de código: pode haver equipes menos disciplinadas e mais relutantes quando se trata de testar. Nesses casos, convém combinar essa métrica com outras, como o número de bugs, o tempo gasto na resolução de bugs ou o número de observações durante as revisões de código.

Você também pode aplicar pelo menos uma cobertura de código, digamos 60% ¹, em projetos individuais onde faz sentido (tenha cuidado para excluir protótipos, código gerado, CRUD, etc.) Possibilitando aos desenvolvedores marcar classes específicas como excluídas da cobertura do código também é bom². Nesse caso, isso pode ser feito sob a forma de uma verificação que falha na compilação se a cobertura do código estiver abaixo do mínimo necessário. Eu faria isso no estágio de construção, não no estágio de confirmação , pois não é esperado que você execute testes de unidade durante o commit .


¹ Eu consideraria 60% como um mínimo razoável, com base na minha base de código: quase todos os projetos ou classes com menos de 60% de cobertura de código são realmente não testados . Isso pode variar muito de um idioma para outro e de uma empresa para outra (em algumas empresas, 0% é um padrão). Certifique-se de discutir com sua equipe o que é normal e o que é alto demais para eles. Talvez eles estejam constantemente atingindo 95% e possam atingir 99% facilmente, ou talvez tenham dificuldade para aumentar sua cobertura de código de 70% para 75%.

² Dado que eventuais abusos serão detectados durante as revisões de código, você não deve ter medo de dar essa possibilidade aos desenvolvedores. Isso é semelhante à possibilidade de excluir algumas partes do código das verificações pelas linhas ou verificadores de estilo. JSLint, StyleCop e Code Analysis são três exemplos em que a exclusão é suportada e é realmente útil sem incentivar o abuso.


Entendo completamente o fato de que impor algumas regras de conclusão é um feito contraproducente, se não impossível. Parece que eu estava pensando muito técnico com uma solução aqui, e talvez se deva a práticas de revisão algumas etapas antes do que discuti acima, como em um estágio de solicitação por solicitação. Eu tinha uma ideia de que isso estava sendo muito rigoroso, mas queria verificar se alguém tem algum método na prática.
Daniel Park

1
As solicitações de recebimento do @DanielPark são uma parte vital do IMO do fluxo de trabalho do GitHub.
RubberDuck

Vou marcar esta resposta como uma resposta sobre outras pessoas, devido às suas conclusões iniciais sobre o contexto de cobertura. Também retirei o argumento de que a cobertura do código é melhor usada como uma medida do que como um critério e, em geral, ter condições em torno dela é muito subjetivo e não excessivamente construtivo por si só. Eu acho que minha direção nesse estágio é envolver a métrica nas fases de solicitação de recebimento e ser adicionalmente escrupuloso para garantir uma cobertura adequada nas áreas certas antes dos lançamentos publicados. Obrigado por todas as respostas.
1155 Daniel Park

"Um simples pedaço de código que lida com um recurso que ninguém usa" talvez devesse ser removido em vez disso?
Rjnilsson

4

Considere o seguinte código:

rsq = a*a + b*b;
if (rsq >= 0.0) {
    r = sqrt(rsq);
}
else {
    handle_this_impossible_event();
}

Não há como criar um caso de teste que alcance esse ramo. No entanto, se esse fosse um software de vôo crítico para a segurança, as pessoas estariam em todo o caso do autor se essa proteção contra o envio de um valor negativo sqrtnão estivesse presente. Normalmente, o cálculo rsq = a*a + b*be a extração da raiz quadrada são separados por várias linhas de código. Enquanto isso, um raio cósmico pode ativar o sinal rsq.

De fato, o software de vôo invocou o equivalente a handle_this_impossible_event()várias vezes. Geralmente, isso envolve alternar o controle para um computador redundante, desligar normalmente o computador suspeito, reiniciar o computador suspeito e, finalmente, o computador suspeito assumindo a função de backup. Isso é muito melhor do que o computador de vôo principal que está ficando louco.

Mesmo em software de vôo, é impossível obter 100% de cobertura de código. As pessoas que afirmam ter conseguido isso têm código trivial ou não têm testes suficientes contra esses eventos impossíveis.


Se ae bforem números inteiros de 32 bits assinados, muitos valores como 65535 e 65535 ou 40000 e 40000 podem resultar rsqnegativos.
David Conrad

2
@ DavidConrad - eu usei 0.0, implicando que ae bsão algum tipo de ponto flutuante. Com o software de vôo, é imperativo proteger contra a raiz quadrada de um número negativo, mesmo se você souber que o número não pode ser negativo. Os raios cósmicos são pequenas coisas desagradáveis. Um experimento muito recente ( lançado há menos de uma semana ) estudará se um supercomputador na Estação Espacial Internacional pode usar software em vez de hardware para proteger contra raios cósmicos (SEUs, etc.).
David Hammen

Justo, eu negligenciei o 0.0.
David Conrad

4

A cobertura do teste é uma métrica útil para a integridade geral do seu projeto. Uma alta cobertura de teste permite que você tome uma decisão informada sobre se o software funcionará conforme o esperado quando implantado; com uma baixa cobertura de teste, o que implica que você está apenas adivinhando. Existem ferramentas para medir a cobertura automaticamente, geralmente funcionam executando o programa em um contexto de depuração ou injetando operações de contabilidade no código executado.

Existem diferentes tipos de testes e diferentes tipos de métricas de cobertura. As métricas de cobertura comuns incluem cobertura de função, cobertura de extrato, cobertura de filial e cobertura de condição, embora haja mais .

  • Os testes de unidade verificam se a implementação de uma unidade conceitual (módulo, classe, método, ...) está de acordo com sua especificação (em TDD, o teste é a especificação). Unidades sem seus próprios testes de unidade são uma bandeira vermelha, embora possam ser cobertas por testes no estilo de integração.

    Os testes de unidade devem implicar cobertura quase total da função - como o teste de unidade exerce toda a interface pública dessa unidade, não deve haver funcionalidade que não seja tocada por esses testes. Se você estiver introduzindo o teste de unidade em uma base de código existente, a cobertura das funções é um indicador aproximado de progresso.

    Um teste de unidade deve buscar uma boa cobertura de declaração (75% a 100%). A cobertura da declaração é uma métrica de qualidade para um teste de unidade. A cobertura total nem sempre é possível e você provavelmente usa melhor o seu tempo do que para melhorar a cobertura além de 95%.

    A cobertura de filial e condição é mais complicada. Quanto mais complicado ou importante for um código, maiores serão essas métricas. Porém, para código não espetacular, a alta cobertura de declaração tende a ser suficiente (e já implica uma cobertura de filial de pelo menos 50%). Examinar o relatório de cobertura de condições de uma unidade pode ajudar a construir melhores casos de teste.

  • Os testes de integração verificam se várias unidades podem funcionar corretamente umas com as outras. Os testes de integração podem ser muito úteis sem pontuar alto em qualquer métrica de cobertura. Enquanto os testes de integração geralmente exercem grande parte das interfaces de suas unidades (ou seja, possuem alta cobertura de funções), os internos dessas unidades já foram cobertos pelos testes de unidade.

A execução de testes antes que o código seja mesclado em uma ramificação principal é uma boa idéia. No entanto, o cálculo das métricas de cobertura de teste para todo o programa tende a demorar muito tempo - esse é um bom trabalho para uma construção noturna. Se você puder descobrir como fazer isso, um bom compromisso seria executar apenas testes alterados ou testes de unidade em unidades alteradas em um gancho Git. As falhas no teste não são aceitáveis ​​para nada além de "trabalhos em andamento" - confirma. Se as métricas de cobertura selecionadas caírem abaixo de algum limite (por exemplo, cobertura de declaração abaixo de 80% ou a introdução de novos métodos sem os testes correspondentes), esses problemas devem ser tratados como um aviso, com uma oportunidade para o desenvolvedor corrigir esses possíveis problemas. No entanto, algumas vezes há boas razões para ignorar esses avisos, e os desenvolvedores devem poder fazer isso.

Os testes são bons, mas muitos deles podem ser irritantes. O feedback rápido e relevante pode ajudar a promover a atenção à qualidade, mas você não deseja que isso atrapalhe a produção de valor. Pessoalmente, prefiro executar testes manualmente, pois isso permite um feedback mais rápido da parte em que estou trabalhando. Antes do lançamento, farei um foco na qualidade em que uso análise estática, perfis e ferramentas de cobertura de código para encontrar zonas problemáticas (com algumas dessas etapas fazendo parte de um conjunto de testes de pré-lançamento).


3

Ninguém mencionou testes de mutação . A idéia por trás deles é bastante prática e intuitiva.

Eles trabalham modificando o código fonte aleatoriamente (por exemplo, alternando ">" para "<") - daí a mutação - e verificando se essas mudanças aleatórias quebram qualquer teste.

Caso contrário, a) o código em questão pode ser desnecessário ou b) (mais provável) que esse trecho de código não seja coberto por um teste, pois a quebra não será detectada.


1

Obviamente, os dados de cobertura de código podem ser obtidos automaticamente, mas nenhuma decisão automática deve ser tomada com base neles, por razões que outros já explicaram. (Muito confuso, muito espaço para erro.)

No entanto, a próxima melhor coisa é ter um processo estabelecido pelo qual o estado atual do projeto em termos de cobertura de código seja regularmente verificado por seres humanos, possivelmente com relatórios diários chegando na caixa de entrada do gerente de projeto.

Em ambientes corporativos, isso é alcançado com as ferramentas de Integração Contínua , como Hudson, Jenkins, etc. Essas ferramentas são configuradas para verificar regularmente todo o projeto no repositório de códigos-fonte, construí-lo, executar os testes e gerar relatórios. Obviamente, eles podem ser configurados para executar os testes no modo de cobertura de código e incluir os resultados nesses relatórios.

O Jetbrains também torna o TeamCity, que me parece um pouco mais leve e adequado para lojas de software menores.

Portanto, o gerente de projeto recebe relatórios regulares de cobertura de código, usa seu próprio bom senso e age como executor, se necessário.


1
Eu não sou o eleitor abatido. Eu suspeito que o voto negativo foi por causa de sua primeira frase. A cobertura do código certamente pode ser verificada automaticamente. Talvez você deva mudar essa frase. O problema em questão é se os resultados desse teste automatizado de cobertura de código devem ser usados ​​de maneira automatizada, por exemplo, em um gancho do Git.
David Hammen

0

A cobertura do código pode ser verificada automaticamente, apesar da opinião popular, o conjunto de ferramentas Purify da Rational incluía um recurso de cobertura do código. Ele dependia de instrumentar todas as funções (trabalhava nos binários, atualizando cada função ou chamada com um pouco de código extra) para poder gravar os dados que foram exibidos ao usuário. Tecnologia muito legal, especialmente na época.

No entanto, mesmo quando tentamos realmente obter 100% de cobertura, conseguimos apenas 70% mais ou menos! Portanto, é um exercício inútil.

No entanto, na situação de escrever testes de unidade, acho que 100% da cobertura de testes de unidade é ainda mais inútil. Teste de unidade aqueles métodos que exigem teste de unidade, nem todo getter ou setter! O teste de unidade deve ser sobre a verificação das funções complicadas (ou classes TBH) e não tentar marcar as caixas em algum processo ou ferramenta que mostre boas marcas verdes.


0

Eu construí uma ferramenta para isso

https://github.com/exussum12/coverageChecker

Usando

bin/diffFilter --phpunit diff.txt clover.xml 70

Falhará se menos de 70% do diff for coberto por testes de unidade.

Obtenha o diff por.

git diff origin/master... > diff.txt

Supondo que você ramificou do mestre e se fundirá novamente no mestre

Ignore a flag phpunit no código, é realmente apenas uma verificação de trevo, para que qualquer coisa que possa produzir trevo possa usá-la.

Como outras respostas sugeriram colocar isso a 100% não é uma boa ideia

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.