I have been hearing that with unit testing we can catch most of the bugs in the code and I really believe that this is true. But my question is in large projects where each class is dependent on many other classes how do you go about unit testing the class ? Stubbing out every other class doesn't make much sense because of both complexity and the time required to write the stubs. What is your opinion about it?
I'm not up to speed on the whole unit testing thing, but I would think that each unit should represent some sort of test. A test case should test some procedure. A procedure may not be confined to a single class.
For instance, if your application can be broken down into atomic components, then a test case could exist for each component and for each applicable chain of transitions between components.
Use a mocking framework to stub your classes for you. Mocking frameworks (I use Rhino Mocks for C#/.NET) make it pretty easy to stub out your dependencies. Used with dependency injection, your classes can be easily decoupled from other classes and don't take much work to make them so. Note that sometimes it does become easier to "fake" something rather than mock. I do end up faking a few classes, but usually these are pretty easy to write -- they just contain "good" or "bad" data and return it. No logic involved.
In our project developers have the responsibility of writing and maintaining stubs right from the start.
Even though stubs cost time and money, unit testing provides some undeniable advantages (and you agreed to it too). It allows for automation of the testing process, reduces difficulties of discovering errors contained in more complex pieces of the application, and test coverage is often enhanced because attention is given to each unit.
With my experience I have seen that in projects where we had put unit testing at low priority had to suffer at a later stage where single change either break things or needs extra testing.
Unit testing increases the confidence in me as a software developer.
Part of the advantage of using tests, is that it forces you to minimize dependencies thereby creating testable code. By minimizing dependencies you will increase maintainability and reusability of your code, both highly desirable traits.
Since you are introducing tests into an existing code-base, you will no doubt encounter many hard-to-test situations which will require refactoring to test properly. This refactoring will increase the testability of your code, decreasing dependencies at the same time.
The reason why its hard to retrofit code with tests is why many advocate following Test-Driven-Development. If you write your tests first and then write the code to pass the tests, your code will by default be much more testable and decoupled.
i prefer to unit test features, which may or may not correspond to individual classes. This granularity of unit testing seems to me to be a better trade-off in the work required for testing, the feedback for the customer (since features are what they pay for), and the long-term utility of the unit tests (embody requirements, illustrate how-to cases)
as a consequence, mocking is rarely required, but some tests span multiple classes
But my question is in large projects where each class is dependent on many other classes how do you go about unit testing the class ?
First, you understand that "each class is dependent on many other classes" is a bad thing, right? And that it isn't a function of having a large project but rather of bad design? (This is one of the benefits of TDD, that it tends to discourage such highly coupled code.)
Stubbing out every other class doesn't make much sense because of both complexity and the time required to write the stubs.
Not to mention that it doesn't help the design problem. Worse, the investment in all the stubs can actually be a hinderance to refactoring, if only a psychological one.
A better approach (IMHO) is to start from inside out on the classes, changing the design as you go. Typically I would approach this by doing what I call "internal dependency injetion". This involves leaving the method signatures unchanged but extracting the data needed from the dependencies and then extracting functions that hold the actual logic. A trivial example might be:
public int foo(A a, B b) {
C c = a.getC();
D d = b.getD();
Bar bar = calculateBar(c, d);
return calculateFoo(bar, this.baz);
}
Bar calculateBar(C c, D d) {
...
}
int calculateFoo(Bar bar, Baz baz) {
...
}
Now I can write a test for calculateBar and calculateBaz, but I don't need to worry in setting up internal states (this.baz) and I don't need to worry about creating mock versions of A and B.
After creating tests like this with the existing interfaces then I look for opportunity to push the changes out to the interface, like changing the Foo method to take C and D rather than A and B.
Any of that make sense?
You're right, stubbing all the classes on which the class you're testing depends on is not worth the effort. And you will have to maintain your mock as well, ifever you change the interfaces.
If the classes used by the one you're testing have already been tested, then it's fine to have a test spanning over several classes.
It sometimes simpler to mock an object : when
- object is or uses an external resource such as database or network connection, disk
- object is a GUI
- object is not [yet] available
- object behavior is not deterministic
- object is expensive to setup