Say you have a database connection provider for production, and a mock persistence layer for testing. This setup is common for iBatis, Hibernate or similar solutions. How should you design the consumers of these? I fell upon this clever pattern today while reworking an event replayer which read events from a database and injected them into a messaging system:
/**
* <code>Foo</code> does something clever. It has two
* modes: production and testing. For production, use {@link
* #Foo(ConnectionProvider)} and pass in a provider. For testing,
* use {@link #Foo(BarMapper)} and pass in a mock mapper.
*
* The code takes great care in the constructors to ensure you cannot mix uses.
* All instance variables are marked <code>final</code>.
*
* If you are in production use, the constructor tests <var>provider</var> and
* assigns it, making the mapper <code>null</code>. Then, if you try to use
* the mapper instance variable directly instead of via the getter for it,
* you will throw a <code>NullPointerException</code>.
*
* Contrariwise, if you are in testing use, the constructor tests the
* mapper parameter and assigns it, making the provider <code>null</code>.
* Then, if you try to use the provider instance variable directly instead of
* via the getter for it, you will throw a <code>NullPointerException</code>.
*
* Lastly, there is no {@link Connection} instance variable. Instead {@link
* #barNone(Id)} gets one from the provider on the fly (the getter
* ensure this only really does something if in production mode), and closes it
* before the method returns. There is never a leak, the connection is never
* held for longer than needed, the method may be run more than once
* statelessly, and the method uses a getter for the mapper, again ensuring
* the code <cite>does the right thing</cite>.
*/
public class Foo {
private final ConnectionProvider provider;
private final BarMapper mapper;
public Foo(final ConnectionProvider provider) {
if (null == provider)
throw new NullPointerException();
this.provider = provider;
this.mapper = null;
}
protected Foo(final BarMapper mapper) {
if (null == mapper)
throw new NullPointerException();
this.provider = null;
this.mapper = mapper;
}
public void barNone(final Id barId) {
final Connection conn = getConnection();
try {
doSomethingCleverHere(barId, getMapper(conn));
} finally {
close(conn);
}
}
private Connection getConnection() {
return null != provider
? provider.getConnection()
: null;
}
private void close(final Connection conn) {
if (null != provider) provider.close(conn);
}
private BarMapper getMapper(final Connection conn) {
return null != mapper
? mapper
: new BarMapper(conn);
}
} See the idea? Several things are going on at once here. Read the class javadoc comment carefully. This trick will serve you well.
A footnote: why is the one constructor public and the other protected? Simple. The constructor taking a connection provider is for production and is marked public. The constuctor taking a mapper is for testing and is marked protected. Remember to keep production and test case code in the same package but in separate source trees.
2 comments:
why not just have one constructor that takes both a provider and a mapper or even just a mapper? code would be much more readable, you can dynamically mock the provider and mapper in tests, and then you have no additional cruft just for the purpose of testing. Having a different way of constructing/using objects for tests is a big smell IMHO.
It turns out that the Provider is very difficult to mock. This is the reason I looked at this approach in the first place. In our production system, the provider makes a database connection, which gets you a result set, etc. The amount of mocking grows very considerably. We refactored the code to limit this so that we could either provide a provider, or provide an easy-to-mock mapper. Hence the two constructors. I should have mentioned this in the original posting.
Post a Comment