5

I'm getting an error: java.lang.ClassCastException: Z cannot be cast to java.lang.String while trying to run coverage (EclEmma) on a Junit test. If I run the test regularly (without coverage) then it passes.

This is the code (all the fields in the class are Strings):

@Override
public Map<String, String> getErrors() throws IllegalAccessException, IllegalArgumentException {

    Map<String, String> errors = new HashMap<String, String>();

    for (Field field : this.getClass().getDeclaredFields()) {
        field.setAccessible(true);
        String value = (String) field.get(this);

        if (value.equals("N")) {
            if (!errors.containsKey(field.getName())) {
                errors.put(field.getName(), value);
            }
        }
    }
    return errors;
}
xenteros
  • 15,586
  • 12
  • 56
  • 91
co.zohar
  • 183
  • 3
  • 15

3 Answers3

8

The problem is that to produce the code coverage EclEmma adds a field private static final transient boolean[] $jacocoData to your class.

Since this field is only present during code coverage runs, the normal unit test passes, but the code coverage run fails: your original code is not expecting this non-String field.

The best solution is to check if the field you are seeing is really a String field and otherwise skipping the test of the field value:

for (Field field : this.getClass().getDeclaredFields()) {
    field.setAccessible(true);
    if (field.getType() != String.class) {
        continue;
    }
    String value = (String) field.get(this);

    if (value.equals("N")) {
        if (!errors.containsKey(field.getName())) {
            errors.put(field.getName(), value);
        }
    }
}
Thomas Kläger
  • 17,754
  • 3
  • 23
  • 34
0

Try to do this:

String value = "null";
if(field.get(this) != null)
    value = field.get(this).toString();

Instead of this:

String value = (String) field.get(this);
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
NatNgs
  • 874
  • 14
  • 25
  • 2
    Note that this might fail if `field.get(this)` is `null`. Better to use `Objects.toString(field.get(this))`. – Andy Turner Aug 18 '16 at 07:42
  • @AndyTurner how can it be, that you're always there and correct and still less than 30k repu? :) – xenteros Aug 18 '16 at 07:46
  • @xenteros 30k rep requires 150 days at daily maximum to reach. If I actually tried to reach that, I doubt I'd still have a job :) – Andy Turner Aug 18 '16 at 07:47
  • @xenteros yes, I do. No, they don't. – Andy Turner Aug 18 '16 at 07:49
  • Thanks @NathaëlNoguès. It worked. Do you have an idea why it worked when I ran a unit test but didn't work when I ran the coverage? – co.zohar Aug 18 '16 at 07:50
  • @Co.zohar I have realy no idea of why it worked in unit tests haha ! I very don't understand what realy was your problem, I just tried to correct a Java common mistake (to cast to `String` instead of using `toString` method) – NatNgs Aug 18 '16 at 07:53
  • This isn't a real fix. The real problem is that the OP is expecting all of his/her fields to be strings. – Oliver Charlesworth Aug 18 '16 at 08:19
  • @OliverCharlesworth Thanks. I added a check if field value is instance of String. – co.zohar Aug 18 '16 at 08:51
0

Finally, I checked that the field value is instance of String and replaced casting to String with the function toString().

String value = null;
Object fieldValue = field.get(this);
if (fieldValue instanceof String) {
    value = fieldValue.toString();
}

if ("N".equals(value)) {
    if (!errors.containsKey(field.getName())) {
        errors.put(field.getName(), value);
    }
}
NatNgs
  • 874
  • 14
  • 25
co.zohar
  • 183
  • 3
  • 15