Menu

#92 "Line not covered" if class implements templated interface

open
nobody
None
5
2008-07-10
2008-07-10
No

I'm using Cobertura 1.9.

I have a class whose declaration is as follows:

@Entity
@Table(name = "utbHandsets")
public class Handset implements Serializable, Comparable<Handset>
{
...
}

It has both a public no-arg constructor as well as a constructor with arguments. The annotations are for Hibernate/Java Persistance.

Using JDK 1.5.0_14:

Cobertura reports the very first line of the class (the line containing "public class..." as being uncovered, even though every executable line in the class (and all the constructors) are being executed multiple times.

If I remove the "Comparable<Handset>" from the class declaration (and make no other changes to either the class or the unit test), Cobertura now reports the "public" line as being covered.

Using JDK 1.6.0_04:

Cobertura reports the "@Entity" line as being uncovered. Again, if I remove the "Comparable<Handset>" from the class declaration (and make no other changes to either the class or the unit test), Cobertura now reports the "@Entity" line as being covered.

So, there's something going on with templated interfaces that results in an unwarranted "line not covered" - the symptom just looks slightly different depending on which JDK did the compiling.

Discussion

  • Pablo Ruggia

    Pablo Ruggia - 2008-11-27

    Same behaviour here.
    Cobertura 1.9
    JDK 1.6

    Thanks !

     
  • Nobody/Anonymous

    We've got what looks like the same problem in version 1.9 as well. Its a real pain because for small classes it means the coverage levels are dropping below the threshold we've set for the builds to pass.

     
  • Keith Treague

    Keith Treague - 2009-08-28

    I am also running against this bug and it is droping coverage below our acceptable levels.

     
  • Adrien

    Adrien - 2009-09-04

    I am having the same issue
    It has something to do with the generics.
    I found that out today and added a bug ticket

     
  • Nobody/Anonymous

    For the record:

    To cover this piece of code you can create a test like:

    Comparable<Handset> handset = new Handset();
    handset.compareTo(otherHandset);

    Works for me with Cobertura 1.9.2. and java 1.6

     
  • Nobody/Anonymous

    If you decompile the generated class (with jad for example) you will notice that
    there are 2 compareTo methods, of which one is volantile.
    This last methods calls the implemented compareTo method.

    So the Cobertura ' line not covered' is correct (if you dont call the method direct from
    the interface) but a little bit confusing

     
  • Kevin Hunter

    Kevin Hunter - 2010-02-17

    For anybody tracking this, it turns out the the issue is a "bridge" function. When you code with generics, implementing Comparable<X> involves adding a function "compareTo(X)". The problem is that, under the hood, even with generics, Comparable defines "compareTo(Object)". So java adds a hidden "compareTo(Object)" function that calls your "compareTo(X)". This is the function that isn't getting covered. (There's a good description of this at http://codeidol.com/java/javagenerics/Comparison-and-Bounds/Bridges/\)

    The solution is to include a test like this:

    Comparable handset = new Handset();
    handset.compareTo(otherHandset);

    Note that the *nongeneric* version of Comparable is used (you'll probably need a @SuppressWarnings("unchecked")). This causes the subsequent compareTo line to use the Object version - the hidden bridge function.

    (Note that the comment entered on 2010-02-03 was on the right track but isn't *quite* correct - that version exercises the compareTo(Handset) method (the one you coded), not the compareTo(Object) (the bridge function).

    So, my earlier statement that there was an "unwarranted line-not-covered" was not correct - there is, indeed, an uncovered function, it's just a little tricky as to why, and how to get it covered. Thus, this is not, in fact, a bug, although perhaps it is worth of an FAQ entry. If I get a chance, maybe I'll write one and submit it.

     
  • Anonymous

    Anonymous - 2010-06-18

    We had this error in our project at work, and to work around it I put in a few more unit tests that ran against the "raw type" method.

    I constructed a shared method as such:

    protected void reflectiveInvokeInstanceMethodWhichTakesObjectWithArgument(final Object instance, final String methodName, final Object arguments) {
    try {
    final Method method = instance.getClass().getMethod(methodName, new Class[]{Object.class});
    method.invoke(instance, arguments);
    } catch (final Exception e) {
    throw new RuntimeException(e);
    }
    }

    And then used it to call the various offending bridge methods that made coverage drop.

    I hope there is a cleaner way to solve this issue coming..

     

    Last edit: Anonymous 2014-10-21

Log in to post a comment.