Reputation: 5660
Below is an code which I need to unit test. I would write 2 unit test cases for getFoo
, one for true(x==5)
and other for false(x==10)
.
My question is do I need to write two unit test functions even for convertWrapper
for true and false case ? In my opinion I should, to ensure that in future someone does not cause a change in convertWrapper, resulting in regression. But just wondering whats considered a widely adopted practice in such cases.
public boolean getFoo(int x) {
return x == 5;
}
public boolean convertWrapper(char ch) {
int x = (int)ch;
return getFoo(x);
}
Upvotes: 1
Views: 429
Reputation: 30310
Why do you think you need to write only two unit tests for getFoo
?
Of course, you know that the method really can only go one of two ways, but the caller doesn't. It might seem ridiculous with a method this trivial, but you need to think in terms of the contract for the method. Maybe you need to test with 5, then 0, then a negative number, then a really high positive number, or whatever other weird case a caller expects you to be able to handle.
Similar with convertWrapper
. You know it calls getFoo
and getFoo
has really only two paths, but you can't let yourself think that way.
The bottom line is you need to define the contract for your methods and run enough tests where you feel confident that your public methods satisfy that contract.
Upvotes: 0
Reputation: 40336
Yes, you probably do want to write separate cases, because your opinion is generally correct and is precisely the type of situation proper testing is meant to avoid:
In my opinion I should, to ensure that in future someone does not cause a change in convertWrapper, resulting in regression.
Your unit tests should test the high-level functionality of your code. Your unit tests are unaware of implementation details, they only test that the terms of the "contract" are met. Since you have two public methods that, on a high level, do two separate things (we presume - your requirements weren't stated or documented), then you have two separate tests.
Eliminating one of the tests because you, as the developer, implicitly know that the implementations are the same suddenly brings information about implementation details into the testing realm, which is asking for problems and regressions in the future.
One option that Dave Newton pointed out in his answer is to write a unit test that essentially ensures that convertWrapper(ch) == getFoo((int)ch)
for all relevant ch
. That is a fine suggestion and may very well be appropriate, but only if the high level requirement of convertWrapper
is that it "returns the same value as getFoo
". Again, your tests should reflect your requirements.
Of course, that doesn't mean it's somehow against the law to eliminate the test. The devil won't necessarily lay claim to your soul if you do it (although sometimes I wish that was the usual consequence). If your application is rather simple, or if you are willing to accept the associated risks, then even a simple "@todo Test me" documentation marker may be enough to get by. It is sometimes OK to take shortcuts now and then but only if you truly understand and accept the implications -- only you can save you from yourself. :)
But, in the general case, yes, two tests. Then you can "fire-and-forget" your tests, and never have to remember that special exception to the rules you made in the future.
Upvotes: 1
Reputation: 79838
Ask yourself - what is the general contract of convertWrapper
. If it's to return true for a particular input, and return false for any other input, then test that it does that. The fact that it is implemented via getFoo
is irrelevant to how you'll unit test it.
If somebody in the future changes the implementation so that it still returns true or false for the same inputs as before, but doesn't use getFoo
then that should NOT break the test.
Since getFoo
is public, it should have its own tests.
Upvotes: 2
Reputation: 533530
Best practice is to write unit tests in general. They should be simple and easy to maintain. If using multiple tests methods is the simplest and easiest to maintain do that. In general, I try not to write too much boiler plate code in unit tests.
Upvotes: 2
Reputation: 160191
One option: ensure convertWrapper calls and returns the result of getFoo, and unit test getFoo.
Mocks help do integration tests like that.
Upvotes: 2