Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should every possible branch in a method have a separate junit?

This is more of a design question.

Suppose you have a method like this (as an example):

if (x == 5) {
  c = 1;
} else {
 if (z != 2) {
  b = 6;
} else {
   a = 3;
}

Do you think it's best practice to have a junit for each possible branch? Ie, testx5, test xnot5znot2, testxnot5z2, etc, or something like:

void testMethod() {
// x is 5
test/assert code;

// x not 5, z not 2
test/assert code;

// x not 5, z is 2
test/assert code

// etc
}

EDIT: Just to be clear, my goal is complete code coverage. I just want to know opinions on whether I should make a new test for each branch or combine them in one test. Thank you for your input.

like image 922
AHungerArtist Avatar asked Nov 08 '11 14:11

AHungerArtist


3 Answers

The JUnit FAQ seems to indicate that it is better to have more tests with fewer assertions, if only because JUnit will only report the first assertion failure in a test method. With one method, if you broke the x = 5 case, you'd have no way to tell if any of the x != 5 cases were still working.

like image 82
Samuel Edwin Ward Avatar answered Nov 15 '22 16:11

Samuel Edwin Ward


What you're discussing is called Branch Coverage.

The conventional wisdom is if it's important enough to write code to cover that use case, it's important enough to write a test case to cover that code. So this would seem to say that 100% branch coverage is an excellent goal (and will also imply 100% statement coverage, but not necessarily 100% loop or 100% condition coverage).

However, you also need to balance the effort of writing tests with the value of getting those tests. For example, if the code you're testing has a try/catch to catch a checked exception, but the exception is almost never thrown (or difficult to cause to be thrown in a test case), then writing a test to cover that exception is probably not worth your time.

This is why you see in a lot of places that aiming for a certain % of test coverage is a bad idea, because you end up writing test cases to get coverage, not to find bugs. In your example, yes, each branch deserves it's own test case. In every piece of production code, it's probably not necessary.

like image 39
Kane Avatar answered Nov 15 '22 16:11

Kane


In unit testing, your goal is to test behaviors -- not the "code". Think of the method you're testing a black box and you want to see if it works correctly. You don't know how it does it's job internally, but you expect certain results for certain inputs. So you'd want to create tests for different cases of how you'd expect the code to work as if you didn't know anything about how the internals of the method actually does it's job. So you'd write tests like "applysDiscountToShoppingCart" and "addsDeliveryFeeToShoppingCart".

Now, all that being said, it's also useful to create "edge cases" in which you're testing things that are likely to break (like nulls, zeros, negatives, data too big/small, etc) to see if it fails in an expected manner too. Usually to write those, you need to know how the method actually works. If you can design tests that will cover all your code, that's great! 100% test coverage is a definite thing to strive for, but it's not always practical (or useful) depending on the situation.

like image 30
Todd Avatar answered Nov 15 '22 17:11

Todd