4

I have 2 pieces of code that are giving me trouble. I test them with Unit-Tests, using cobertura to analyze the test coverage, and I don't understand how the conditional coverage is computed. This is the first piece:

if ((x.getInt() == a) 
 || (x.getInt() == y.getInt()) { ...

Cobertura reports me that 4 cases need to be covered, which seems fine when assumed that short-circuiting is ignored.

Then, in another method I have another (longer) conditional:

if ((x == null)
 || ObjectUtils.equals(x.getInt(), a)
 || ObjectUtils.equals(x.getInt(), y.getInt())) {
  ...

Here comes the part I don't understand: Cobertura reports that 5/6 cases are covered. I would have expected 8 cases, I could explain 5 cases (considering the x == null), but

how does cobertura handle conditional coverage in these cases, and why does that lead to 6 cases?

Mike B.
  • 190
  • 1
  • 9
  • You're thinking of full path coverage and/or branch coverage. For conditional coverage, each boolean expression needs to be evaluated to true and false (two different test cases). If you have three boolean expressions, then you have 6 cases. It's explained well in the wikipedia article on [code coverage](http://en.wikipedia.org/wiki/Code_coverage). – monex0 Jul 01 '14 at 02:41

1 Answers1

1

Coverage is not measured by testing all possible combinations of boolean flag states, but only those combinations which are sufficient to cover all use cases.

Consider the following class:

public class MyClass {

public boolean allOr(boolean x, boolean y) {
    return x || y;
}

public boolean allOr(boolean x, boolean y, boolean z) {
    return x || y || z;
}

public boolean allOr(boolean w, boolean x, boolean y, boolean z) {
    return w || x || y || z;
}

public boolean allAnd(boolean x, boolean y) {
    return x && y;
}

public boolean allAnd(boolean x, boolean y, boolean z) {
    return x && y && z;
}

public boolean andOr(boolean x, boolean y, boolean z) {
    return x && y || z;
}

public boolean orAnd(boolean x, boolean y, boolean z) {
    return (x || y) && z;
}

}

The tests which provide complete coverage are as follows:

public class MyClassTest {

@Test
public void testAllOr2() {
    MyClass instance = new MyClass();
    // For OR clause, test that all false returns false
    assertFalse(instance.allOr(false, false));
    // For OR clause, test that any one true returns true
    assertTrue(instance.allOr(false, true));
    assertTrue(instance.allOr(true, false));
}

@Test
public void testAllOr3() {
    MyClass instance = new MyClass();
    // For OR clause, test that all false returns false
    assertFalse(instance.allOr(false, false, false));
    // For OR clause, test that any one true returns true
    assertTrue(instance.allOr(false, false, true));
    assertTrue(instance.allOr(false, true, false));
    assertTrue(instance.allOr(true, false, false));

    // These do not add to coverage
    // assertTrue(instance.allOr(false, true, true));
    // assertTrue(instance.allOr(true, false, true));
    // assertTrue(instance.allOr(true, true, false));
    // assertTrue(instance.allOr(true, true, true));
}

@Test
public void testAllOr4() {
    MyClass instance = new MyClass();
    // For OR clause, test that all false returns false
    assertFalse(instance.allOr(false, false, false, false));
    // For OR clause, test that any one true returns true
    assertTrue(instance.allOr(false, false, false, true));
    assertTrue(instance.allOr(false, false, true, false));
    assertTrue(instance.allOr(false, true, false, false));
    assertTrue(instance.allOr(true, false, false, false));
}

@Test
public void testAllAnd2() {
    MyClass instance = new MyClass();
    // For AND clause, test that all true returns true
    assertTrue(instance.allAnd(true, true));
    // For AND clause, test that any one false returns false
    assertFalse(instance.allAnd(true, false));
    assertFalse(instance.allAnd(false, true));
}

@Test
public void testAllAnd3() {
    MyClass instance = new MyClass();
    // For AND clause, test that all true returns true
    assertTrue(instance.allAnd(true, true, true));
    // For AND clause, test that any one false returns false
    assertFalse(instance.allAnd(false, true, true));
    assertFalse(instance.allAnd(true, false, true));
    assertFalse(instance.allAnd(true, true, false));
}

@Test
public void testAndOr() {
    MyClass instance = new MyClass();
    // Since AND takes precedence,
    // OR is the external operator, AND is the internal operator
    // For the AND clause, false can be achieved in two ways
    // Compare to testAllAnd2 # 2, 3
    assertFalse(instance.andOr(true, false, false));
    assertFalse(instance.andOr(false, true, false));
    // This completes the first test case for the external operator
    // Compare to testAllOr2 # 1

    // Now irrespective of the arguments
    // as long as the value returned by the internal operation is false
    // we can perform the testAllOr2 # 2
    assertTrue(instance.andOr(true, false, true));
    // We do not need the case for false, true, true
    // because we have tested that no matter what the first two args are
    // it does not make a difference as long as one of them is false

    // However, if both args are true
    // the value returned by the internal operation is true
    // we can perform the testAllOr2 # 3
    // This is only possible in one way
    // Compare testAllAnd2 # 1
    assertTrue(instance.andOr(true, true, false));
}

@Test
public void testOrAnd() {
    MyClass instance = new MyClass();
    // Since OR takes precedence,
    // AND is the external operator, OR is the internal operator
    // For the OR clause, true can be achieved in two ways
    // Compare to testAllOr2 # 2, 3
    assertTrue(instance.orAnd(false, true, true));
    assertTrue(instance.orAnd(true, false, true));
    // This completes the first test case for the external operator
    // Compare to testAllAnd2 # 1

    // Now irrespective of the arguments
    // as long as the value returned by the internal operation is true
    // we can perform the testAllAnd2 # 2
    assertFalse(instance.orAnd(false, true, false));
    // We do not need the case for true, false, false
    // because we have tested that no matter what the first two args are
    // it does not make a difference as long as one of them is true

    // However, if both args are false
    // the value returned by the internal operation is false
    // we can perform the testAllAnd2 # 3
    // This is only possible in one way
    // Compare testAllOr2 # 1
    assertFalse(instance.orAnd(false, false, true));
}

}
Neel
  • 2,100
  • 5
  • 24
  • 47