Donut Classes
Moving inside the donut, we also sometimes need to swap out objects that are used internally by the servlet — and
those objects aren't conveniently passed into the servlet as arguments, as was the case with the request and response objects.
The key to providing test objects to take the place of the objects that the OUT uses is using some variant of the Factory design pattern. A Factory is an object whose job is to make other objects. The simplest possible Factory replaces
SomeClass object = new SomeClass( "arg" );
with
class SomeClassFactory
{ public static SomeClass create( String arg )
{ return new SomeClass( arg );
}
}
//...
SomeClass object = SomeClassFactory.create( "arg" );
It's better, if you can, to make the Factory into an "Abstract" factory, which returns created objects in terms of the interfaces
that they implement. For example, the following factory creates SomeClass objects, but the factory itself returns these
objects in terms of an interface, not actual class name. That way, you can write your code in terms of interfaces, rather than
concrete classes, which makes the code much more flexible. At some point in the future, you can then rewrite the factory to
return some other class, and as long as that new class implements the required interface, the factory's clients don't care that the
actual class that they're using has changed.
class SomeClass implements SomeInterface
{
boolean doSomething( );
{ //...
}
}
class SomeInterfaceFactory
{ public static SomeInterface create( String arg )
{ return new SomeClass( arg );
}
}
//...
SomeInterface object = SomeInterfaceFactory.create( "arg" );
From a testing point of view, the main advantage of a factory approach is that you can easily mock the factory's create() method.
For example, given this code to test:
class ClassUnderTest
{
public void someMethod()
{
SomeInterface donutObject = SomeInterfaceFactory.create("Hello");
//...
}
}
Our test can use PowerMock to change the class of the donutObject into something that's testable. For
example, the following code changes the behavior of the earlier SomeInterfaceFactory
to create mock objects rather than real ones. The mock object is defined in the first two
lines (doSomething() always returns false). The next two lines change the behavior of
create() to return the mockImplemenation instead of creating a normal object,
and the final two lines are the actual test. someMethod() will use the mockImplemenation object.
@RunWith(PowerMockRunner.class)
@PrepareForTest( SomeInterfaceFactory.class )
public class JDBCTest extends PowerMockito
{
@Test
public void myTest()
{
SomeInterface mockImplementation = mock( SomeClass.class );
when( mockImplementation.doSomething() ).thenReturn( false );
mockStatic( SomeInterfaceFactory.class );
when( SomeInterfaceFactory.create( Mockito.anyString() ).thenReturn( mockImplementation );
//...
ClassUnderTest objectUnderTest = new ClassUnderTest();
objectUnderTest.someMethod(); // uses the mock
}
}


