Gostaria de saber se a medição da cobertura condicional do código pelas ferramentas atuais para Java não é obsoleta desde que o Java 8 surgiu. Com o Java 8 Optional
e Stream
muitas vezes podemos evitar ramificações / loops de código, o que facilita obter uma cobertura condicional muito alta sem testar todos os caminhos de execução possíveis. Vamos comparar o código Java antigo com o código Java 8:
Antes do Java 8:
public String getName(User user) {
if (user != null) {
if (user.getName() != null) {
return user.getName();
}
}
return "unknown";
}
Existem 3 caminhos de execução possíveis no método acima. Para obter 100% de cobertura condicional, precisamos criar 3 testes de unidade.
Java 8:
public String getName(User user) {
return Optional.ofNullable(user)
.map(User::getName)
.orElse("unknown");
}
Nesse caso, as ramificações estão ocultas e precisamos apenas de 1 teste para obter 100% de cobertura e não importa em que caso iremos testar. Embora ainda existam os mesmos três ramos lógicos que devem ser abordados, acredito. Eu acho que isso torna as estatísticas de cobertura condicional completamente não confiáveis hoje em dia.
Faz sentido medir a cobertura condicional do código Java 8? Existem outras ferramentas para detectar código não testado?
fonte
getName
? Parece que, seuser
for nulo, deve retornar "desconhecido". Seuser
não for nulo euser.getName()
for nulo, deve retornar "desconhecido". Seuser
não for nulo euser.getName()
não for nulo, deve retornar isso. Então você testaria esses três casos, porque é disso quegetName
trata o contrato . Você parece estar fazendo isso ao contrário. Você não deseja ver as filiais e escrever os testes de acordo com eles, deseja escrever seus testes de acordo com o seu contrato e garantir que o contrato seja cumprido. É quando você tem uma boa cobertura.Respostas:
Eu não estou ciente de nenhum. Tentei executar o código que você possui através do JaCoCo (também conhecido como EclEmma) apenas para ter certeza, mas ele mostra 0 ramificações na
Optional
versão. Não conheço nenhum método de configurá-lo para dizer o contrário. Se você o configurasse para incluir também arquivos JDK, teoricamente mostraria ramificaçõesOptional
, mas acho que seria bobagem começar a verificar o código JDK. Você apenas tem que assumir que está correto.Eu acho que a questão principal, no entanto, é perceber que as ramificações adicionais que você tinha antes do Java 8 eram, de certa forma, ramificações criadas artificialmente. O fato de eles não existirem mais no Java 8 significa apenas que agora você tem a ferramenta certa para o trabalho (neste caso
Optional
). No código pré-Java 8, você tinha que escrever testes de unidade extras para ter certeza de que cada ramo do código se comporta de maneira aceitável - e isso se torna um pouco mais importante em seções de código que não são triviais como oUser
/getName
exemplo.No código Java 8, você está confiando no JDK que o código funciona corretamente. Como é, você deve tratar essa
Optional
linha da mesma forma que as ferramentas de cobertura de código a tratam: 3 linhas com 0 ramificações. O fato de haver outras linhas e ramificações no código abaixo é algo que você nunca prestou atenção antes, mas existe sempre que você usa algo como umArrayList
ouHashMap
.fonte
if
enull
ainda são partes da linguagem ;-) Ainda é possível escrever código na maneira velha e passarnull
usuário ou usuário comnull
nome. Seus testes devem apenas provar que o contrato é cumprido, independentemente de como o método é implementado. O ponto é que não há ferramenta para dizer se você testou totalmente o contrato.Optional
(e métodos relacionados) funcionam, não precisa mais testá-los. Não da mesma maneira que você testou umif-else
: todoif
era um campo minado em potencial.Optional
e expressões funcionais semelhantes já estão codificadas e garantidas para não tropeçar em você, portanto, essencialmente, há um "ramo" que desapareceu.Optional
. Como ele disse, logicamente ainda devemos testar segetName()
lida com várias entradas possíveis da maneira que pretendemos, independentemente de sua implementação. É mais difícil determinar isso sem as ferramentas de cobertura de código, ajudando da maneira que seria antes do JDK8.if-else
porque cada uma dessas construções é completamente ad-hoc. Em contraste,Optional
,orElse
,map
, etc, são todos os já testados. Os galhos, na verdade, "desaparecem" quando você usa expressões mais poderosas.