About StubOut

StubOut is a small extension to JUnit that lets you replace Java classes, or parts of classes, for the duration of your unit tests. This is especially helpful when the code you are testing uses classes that were not written with testing in mind. You can stub out those classes within the test, and thus exercise your code in isolation from them.

StubOut is intended to be one of many tools to help you write effective unit tests for your Java code. Ideally, you will never need it. But when you are required to use code that can't easily be mocked out, StubOut offers a simple alternative.

System Requirements

StubOut requires Java 1.4 or later, and JUnit 3.8 or later.

In a Nutshell

StubOut offers two different ways to stub out code. You can replace an entire class with a stub version of it. Or you can replace individual methods of a class.

Replacing an entire class is easier to understand, but less flexible. The idea is to write a replacement version of the offending class that behaves better. For example, the class you need to stub out might be a singleton that connects to a database in its constructor (a bad thing from a unit-testing point of view). Your replacement would have to implement whatever methods from the bad class that your code used, but could otherwise be free from outside dependencies.

Replacing methods is done by associating a stub object with a given class. Any methods implemented by the stub's class are called in place of the original class's versions of those methods. For example, if you provided a stub object that implemented a toString method, and the replaced class also had a toString method, your stub object's toString would be called whenever any instance of the replaced class had its toString method called. The replaced methods can be public or private, instance-level or static. All that matters is that the method names, return types, and argument types all match.

Replacing methods is more flexible than replacing a whole class, because it is done on the fly. Replacing a whole class is done before any tests are run, and applies to all the tests in a test class, whereas replacing methods is done from within a test method, and so can be different from one test method to the next.

However, you can't replace individual constructors or static initializers, only regular methods. So replacing the entire class is sometimes required. Also, if a particular class needs to be stubbed out by multiple tests, it can be easier to write a replacement class once and use it everywhere it is needed.

Examples

Check out the Test Source Cross Reference for some examples of StubOut in action. In particular, look at TestClassReplacement and TestMethodReplacement to see the two approaches at work.

Using StubOut with JUnit 3

To use StubOut, simply make your test class inherit from StubbingTestCase, and then follow the usual JUnit 3 method-naming conventions. You will be able to run your class from within your IDE as usual, or from Ant, or however you run your standard JUnit tests.

To stub out whole classes, you must override the method beforeReloading and within it call Stubber.replaceClass for each class you need to replace.

To stub out individual methods, call Stubber.replaceMethods from a test method or from your setUp method. If you want to undo those method replacements within the test, call Stubber.restoreMethods or Stubber.restoreAllMethods. (All method replacements are restored before each test is run.) See the JavaDocs for more details.

Using StubOut with JUnit 4

StubOut provides a JUnit 4 test runner called StubbingRunner. Annotate your test class with @RunWith(StubbingRunner.class) to use it, like any other test runner.

The analog to the beforeReloading method is an annotation within StubbingRunner called BeforeReloading. Annotate a public static method with this to stub out whole classes.

Stubbing individual methods works exactly the same as for JUnit 3.

StubbingRunner provides a nested annotation also called RunWith, so that after your test class has been reloaded by the stubbing class loader it can be run with a different runner. You can see this in action in the Test Source Cross Reference -- see TestStubbingRunner.

Using StubOut in Combination with Other Testing Tools

There is no conflict between StubOut and other tools like jMock and jDummy. In fact, StubOut comes with built-in support for these two tools, in the form of special JUnit 3 test case superclasses, StubbingMockObjectTestCase and StubbingJDummyTestCase respectively. These provide all the capabilities of StubOut and the other tool.

And there is no reason other tools could not be added to this mix. If you examine the implementations of these test case superclasses you will see that they are very simple, and essentially identical to the core StubbingTestCase class. All of the actual work is done by the Stubber class, independent of any test case implementation.

Acknowledgement

StubOut grew out of the need to replace certain classes to test other classes. I found myself simply re-implementing these classes within my test source directories, to make my code testable. While this approach is workable, it is also problematic: the stub versions of the classes in question might find their way into the actual application if your classpath is set up wrong.

In doing due diligence on this problem, before undertaking a new open-source project, I came across JUnitAssist, a closed-source project that had similar aims, written by Tobias Hill of Citerus AB. His approach was the method replacement technique. I decided having two ways to stub out classes beat having one, so I incorporated his idea into StubOut. Thank you, Tobias.