Pergunta

Eu recentemente comecei a usar ferramentas de cobertura de código (particularily Emma e EclEmma), e eu realmente gosto da ideia de que ele me dá quanto à integralidade dos meus testes de unidade - ea capacidade de ver o que áreas do código minha unidade testes não estão batendo em tudo. Eu atualmente trabalho em uma organização que não fazer um monte de testes de unidade, e eu pensando em realmente empurrando todos para assumir o teste de unidade e de cobertura de código e TDD e esperamos converter a organização.

Uma questão que não estou certo de com este assunto é exatamente o quão longe eu deveria tomar a minha cobertura de código. Por exemplo, se eu tenho uma classe como esta:

//this class is meant as a pseudo-enum - I'm stuck on Java 1.4 for time being
public final class BillingUnit {

    public final static BillingUnit MONTH = new BillingUnit("month");
    public final static BillingUnit YEAR = new BillingUnit("year");

    private String value;

    private BillingUnit(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }

    public boolean equals(Object obj) {
        return value.equals(((BillingUnit) obj).getValue());

    }

    public int hashCode() {
        return value.hashCode();
    }
}

Eu escrevi alguns testes de unidade simples para se certificar de que equals() funciona corretamente, que getValue() retorna o que eu esperava, etc. Mas graças à natureza visual de EclEmma, ??o método hashcode() aparece como vermelho brilhante para "não testado".

Vale a pena sequer se preocuparam em hashCode() teste, neste exemplo, considerando o quão simples a implementação é? Eu sinto que seria adicionar um teste de unidade para este método simplesmente bater a cobertura de código%, e se livrar do destaque vermelho gritante que EclEmma acrescenta a estas linhas.

Talvez eu esteja sendo neurótica e TOC-like, mas eu acho que usando algo como EclEmma que o torna tão fácil de ver o que é testado - os destaques do plugin o código-fonte em vermelho, e o código coberto em verde - realmente faz me quer empurrar para obter o maior número de aulas 100% verde como eu posso - mesmo quando ele não acrescenta muito de um benefício

.
Foi útil?

Solução

Eu uso a cobertura de código para me dar dicas sobre lugares onde eu possa ter um conjunto incompleto de testes. Por exemplo, eu posso escrever um teste para alguns dada funcionalidade, então vá desenvolver o código que satisfaz essa funcionalidade, mas ao fazê-código para realmente escrever que faz mais do que é suposto - dizem que pode capturar uma exceção em um caso alternativo que o teste não exerce. Quando eu uso o analisador de cobertura, eu posso ver que eu introduziu um código que não tem um teste associado. Isso me ajuda a saber quando eu não escrevi testes suficientes.

Por outro lado, a análise de cobertura pode levar a falsa segurança. Ter todo o seu código coberto não significa que você tem provas suficientes. Você precisa pensar sobre os testes a partir da perspectiva do que deve o código e fazer testes de gravação para se certificar de que ele faz isso. De um modo preferido, escrevendo o teste primeiro. Só porque seu código é completamente coberto não significa que o código faz o que é suposto fazer.

No seu exemplo, eu teria escrito o teste para hashCode para definir o que a funcionalidade do método faz, antes de escrever o código. Portanto, eu gostaria que fosse coberto. Isso não significa que eu sempre tenho 100% de cobertura. Eu não sou excessivamente zelosos sobre a escrita de testes para acessores simples, por exemplo. Eu também pode não métodos de teste de classe pai onde eu herdar de um quadro, uma vez que eu não sinto a necessidade de testar outras pessoas do código.

Outras dicas

Eu acho que vale a pena usar uma biblioteca onde você pode escolher ignorar certos tipos de declarações. Por exemplo, se você tem um monte de:

if(logger.isDebugEnabled()) {
    logger.debug("something");
}

É útil se você pode desligar cálculos de cobertura para esses tipos de linhas. Ele também pode ser (possivelmente) válido para desligar cálculos de cobertura para getters e formadores triviais (aqueles que simplesmente definir ou devolver uma variável membro com nenhuma outra verificação ou efeitos colaterais). No entanto eu acho que se você tem equals e hashcode, aqueles devem ser testados. Você adicionou funcionalidade não trivial, e deve ser testado.

Só para ficar claro, a razão que eu acho que as situações acima devem ser excluídos da cobertura é que:

  • Não testar essa funcionalidade é ok. Você não deveria ter que percorrer todo o seu conjunto de testes 5 vezes, com o conjunto de biblioteca de registro para cada nível de registo, apenas para se certificar de que todas as suas declarações são sucesso.
  • Se você fez o acima, seria distorcer a sua cobertura para o outro lado. Se 90% dos seus ramos são if(log.isDebugEnabled()), e você testá-los todos, mas há outros ramos, vai parecer que você tem 90% de cobertura ramo (bom), quando, na realidade, você tem cobertura ramo não-trivial 0% (mau !! ).

Há uma diferença entre a cobertura de código e cobertura de teste. Você deve tentar garantir que seu código está adequadamente testados em vez de ter cobertura de código 100%.

Considere o seguinte código:

public float reciprocal (float ex)
{
    return (1.0 / ex) ;
}

Se você executou um teste que passou em um valor de 1,0, em seguida, você teria 100% de cobertura de código (ramo e declaração) com todos os passes. O código, obviamente, tem um defeito.

Medição de cobertura de teste é mais difícil e que vem de se tornar um desenvolvedor melhor e testador.

Com relação à hashCode especificamente, um truist diria que você deve ter um teste de unidade separada para esse método. Eu, pessoalmente, seria garantir que ele é incluir em pelo menos um teste de unidade-integração e não testar cada assessor / modificador diretamente. O retorno sobre o investimento é muitas vezes demasiado baixo para justificar o esforço. Isso supõe, é claro que você havea teste de unidade que garantir que você está gerando o código hash correto.

Alcançar a cobertura de código 100% com significativa testes podem não valer a pena a subida, e, como mencionado antes, 100% de cobertura de código não significa necessariamente que todas as possíveis condições na aplicação ter sido testado.

Como para testar equals, hashCode e alguns outros contrato com base as interfaces, como Comparable e Serializable, eu incluir esses testes. É importante que o contrato equals/hashCode é implementado corretamente, mesmo com equals/Comparable.

JUnit-Complementos , especialmente

Pode não ser muito complicado agora, mas uma verificação simples para verificar se ele ainda está funcionando como esperado pode ser muito útil mais tarde, se o método é modificado.

Uma vez que o cheque deve ser muito fácil de escrever, por que não fazê-lo? Ele ajuda as estatísticas, e também ajuda a dar-lhe uma verificação mais tarde, apenas em caso de quebra.

Além disso, para TDD, você gostaria de cobertura de 100%, porque então você pode ter certeza (ou muito próximo a ele) que você não está quebrando alguma coisa quando você refatorar.

Um programador companheiro preso como eu em Java1.4 velho;)

Como disse no meu anterior responder , código coberto código não é testada. E a conclusão foi: a partir de um certo ponto, a única maneira de melhorar a cobertura de código é ... ao código de exclusão

!

Agora, quanto hashCode, é interessante tê-lo coberto em um projeto de teste de unidade para verificar o mecanismo ordenada esperado é respeitado (e não para cobrir mais uma função)

Como eu já disse em outro lugar, baixa de cobertura de código é um problema, mas alta de cobertura de código não significa que você está escrevendo ouro puro.

Se você não estavam preocupados sobre o código-cobertura, então eu sugiro que você precisa de testes para equals() e getValue() - dependendo de como e onde hashCode() está sendo usado (desculpe, eu sou um desenvolvedor C #), então você pode quiser testar isso.

A parte mais importante é que os testes de dar-lhe a confiança que você tenha escrito o código de direito e que o código funciona como esperado.

Neste caso particular, eu diria que desde que você está testando o método é igual, assim como você pode Também teste que objetos iguais têm hashcodes iguais: basta adicionar um teste extra para todos os casos em que é igual é esperado para retornar verdadeiro .

Isso vai dar-lhe cobertura de código, e ainda por cima ele vai te dar alguma confiança de que hashCode na verdade satisfaz seu contrato: -)

É apenas marginalmente vale a pena, uma vez que você obviamente pode confiar o método hashCode da corda, e você não espera nunca para mudar esta classe. Mas se você é o suficiente suspeito do seu método equals para testá-lo em tudo, então você deve ser o suficiente suspeita de que ele teste que e hashCode permanecem consistentes. E você deve sempre ser suspeito de pressupostos que você não vai, no futuro, quer mexer sobre com o que você fez antes. Por exemplo, se alguém vem e decide 'otimizar', adicionando uma verificação de ponteiro-a igualdade, então você pode muito bem ter um conjunto completo de testes para eles para executar o seu código modificado contra. Caso contrário, eles vão perder tempo com a mesma preocupação que você fez? - é OK, que eu não tenho cobertura de código

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top