2

I am stuck in a situation where I am not able to fix the 1 of 6 branches issue. Below is the small code I tried to produce

package org.example;

public class Testing {

    public static final String ONE = "1";

    public static boolean condition(String x, boolean y, String z) {
        return "ABC".equalsIgnoreCase(x) 
                && (y  || ONE.equals(z));
    }
}

Test case:

package org.example;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

class BranchCoverageTest {

    @Test
    public void testCondition_xIsABC_yTrue_zNotEqualOne() {
        // Testing the case where the first branch is true, but the second branch is false
        // "ABC".equalsIgnoreCase("ABC") is true, but (true || "1".equals("1")) is true
        assertTrue(Testing.condition("ABC", true, "1"));
    }

    @Test
    public void testCondition_xIsNotABC_yFalse_zEqualsOne() {
        // Testing the case where the first branch is false, but the second branch is true
        // "ABC".equalsIgnoreCase("DEF") is false, but (false || "1".equals("1")) is true
        assertFalse(Testing.condition("DEF", false, "1"));
    }

    @Test
    public void testCondition_xIsNotABC_yFalse_zNotEqualOne() {
        // Testing the case where both branches are false
        // "ABC".equalsIgnoreCase("DEF") is false, and (false || "1".equals("XYZ")) is false
        assertFalse(Testing.condition("DEF", false, "XYZ"));
    }

    @Test
    public void testCondition_xIsABC_yFalse_zNotEqualOne() {
        // Testing the case where the first branch is true, but the second branch is false
        // "ABC".equalsIgnoreCase("ABC") is true, and (false || "1".equals("XYZ")) is false
        assertFalse(Testing.condition("ABC", false, "XYZ"));
    }
}

enter image description here

5
  • 2
    there are 3 conditions, so there (at least¹) are 8 (2*2*2) combinations to be tested... I see 4 - considering the first element being "ABC", we got 4 cases to test; only 2 are being tested || ¹ not counting upper/lower-case alternatives (first parameter) Commented Mar 3 at 17:51
  • @user85421 when you say at least, do you mean at most? && and || can short-cut. Commented Mar 3 at 19:33
  • The comments in you first test method are very misleading. Commented Mar 3 at 19:39
  • @Sören no, I indeed mean "at least", as I wrote 3 conditions and additionally ignored case. I usually do not write my tests (solely) based on the code¹ being tested, but on specification/functionality (and even if done based on code, code is ignoring case, we at least got an additional condition, if we can call that so). And, even considering short-cut, as we can see in the question, it is not testing all cases: quoting myself "considering the first element being "ABC", we got 4 cases to test; only 2 are being tested" || ¹ ... Commented Mar 3 at 20:31
  • ... to test a simple add method I would never be happy having only one single test like add(1, 2) == 3 it could be implemented as int add(int x, int y) { return 1 + 2; } (intentional absurd example - and I am well aware that often it is not possible/feasible to test all combinations) Commented Mar 3 at 20:39

2 Answers 2

1

I was able to fix it by using below test cases

package org.example;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

class BranchCoverageTest {

    @Test
    public void testCondition_XEqualsABC_YTrue() {
        // x = "ABC", y = true, z = "any"
        // true, true, false
        assertTrue(Testing.condition("ABC", true, "any"));
    }

    // Done
    @Test
    public void testCondition_XEqualsABC_YFalse_ZEqualsOne() {
        // x = "ABC", y = false, z = "1"
        // true, false, true
        assertTrue(Testing.condition("ABC", false, "1"));
    }

    // Done
    @Test
    public void testCondition_XEqualsABC_YFalse_ZNotOne() {
        // x = "ABC", y = false, z = "not 1"
        // true, false, false
        assertFalse(Testing.condition("ABC", false, "not 1"));
    }

    
    @Test
    public void testCondition_XNotEqualsABC() {
        // x = "DEF", y = true, z = "any"
        // false, true, false
        assertFalse(Testing.condition("DEF", true, "any"));
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

You might want to add what was missing in your existing test cases, and why adding these four fixes this. (I suspect you only need the second one. Or maybe the first two.)
0

Interesting case. There are various adequacy criteria you could target.

For clarity: there are 3 conditions here (x = ABC, y = true, and z = 1), and the overall predicate (which can yield true or false).

Possible targets:

  • Just the predicate: All you want is that the predicate yields true and yields false. This can be achieved by just two test cases (e.g., one with x = ABC and one in which x!= ABC, and for both y=true and z=1)

  • Every condition true or false: All you want is that each individual condition is true as well as false in at least one test case. This can be achieved with just two test cases (x=ABC, y=false, z=2, and x=AAA, y=true, z=1). Note in this case the predicate outcome is "false" in both cases.

  • MC/DC or Modified Condition/Decision Coverage, in which you ensure that each condition individually flips the predicate outcome. With three conditions you'd have four test cases -- for example:

    • T1: x = ABC, y = false, z = 1, predicate result true
    • T2: x != ABC, y = false, z = 1, predicate result false (first condition flips w.r.t. T1)
    • T3: x = ABC, y = true, z = 1, predicate result false (2nd condition flips w.r.t. T1)
    • T4: x != ABC, y = false, z = 2, predicate result false (3rd condition flips w.r.t. T1)
  • Full condition coverage: where you insist on trying all 2^3 = 8 combinations -- the most exhaustive, and the most expensive.

Note that the final test suite provided in the answer is (very similar to) the MC/DC cover.

The 'branches' as mentioned by JaCoCo correspond in this case to individual conditions. You can think of them in branches of a tree for the short-circuit evaluation of the expression.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.