Reputation: 1921
I'm looking to better understand I should test functions that have many substeps or subfunctions.
Let's say I have the functions
// Modify the state of class somehow
public void DoSomething(){
DoSomethingA();
DoSomethingB();
DoSomethingC();
}
Every function here is public. Each subfunction has 2 paths. So to test every path for DoSomething()
I'd have 2*2*2 = 8 tests. By writing 8 tests for DoSomething()
I will have indirectly tested the subfunctions too.
So should I be testing like this, or instead write unit tests for each of the subfunctions and then only write 1 test case that measures the final state of the class after DoSomething()
and ignore all the possible paths? A total of 2+2+2+1 = 7 tests. But is it bad then that the DoSomething()
test case will depend on the other unit test cases to have complete coverage?
Upvotes: 4
Views: 2451
Reputation: 518
Definitely test every subfunction seperately (because they're public). It would help you find the problem if one pops up.
If DoSomething only uses other functions, I wouldn't bother writing additional tests for it. If it has some other logic, I would test it, but assume all functions inside work properly (if they're in a different class, mock them).
The point is finding what the function does that is not covered in other tests and testing that.
Upvotes: 1
Reputation: 1272
Indirect testing should be avoided. You should write unit tests for each function explicitly. After that You should mock submethods and test your main function. For example :
You have a method which inserts a user to DB and method is like this :
void InsertUser(User user){
var exists = SomeExternal.UserExists(user);
if(exists)
throw new Exception("bla bla bla");
//Insert codes here
}
If you want to test InsertUser function, you should mock external/sub/nested methods and test behaviour of InsertUser function.
This example creates two tests:
1 - "When user exists then Should throw Exception"
2 - "When user does not exist then Should insert user"
Upvotes: 0
Reputation: 61959
There appears to be a very prevalent religious belief that testing should be unit testing. While I do not intend to underestimate the usefulness of unit testing, I would like to point out that it is just one possible flavor of testing, and its extensive (or even exclusive) use is indicative of people (or environments) that are somewhat insecure about what they are doing.
In my experience knowledge of the inner workings of a system is useful as a hint for testing, but not as an instrument for testing. Therefore, black box testing is far more useful in most cases, though that's admittedly in part because I do not happen to be insecure about what I am doing. (And that is in turn because I use assertions extensively, so essentially all of my code is constantly testing itself.)
Without knowing the specifics of your case, I would say that in general, the fact that DoSomething()
works by invoking DoSomethingA()
and then DoSomethingB()
and then DoSomethingC()
is an implementation detail that your black-box test should best be unaware of. So, I would definitely not test that DoSomething()
invokes DoSomethingA()
, DoSomethingB()
, and DoSomethingC()
, I would only test to make sure that it returns the right results, and using the knowledge that it does in fact invoke those three functions as a hint I would implement precisely those 7 tests that you were planning to use.
On the other hand, it should be noted that if DoSomethingA()
and DoSomethingB()
and DoSomethingC()
are also public functions, then you should also test them individually, too.
Upvotes: 4