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