Another question - setting up a mock DB connection

93 views
Skip to first unread message

Adam Schaible

unread,
Nov 2, 2007, 9:38:18 AM11/2/07
to google-guice
Hello everyone,

Thanks again, in advance -

I'm pulling the never-ending thread discussed in the user's guide, and
I noticed yet another place where my code could be refactored.

I have an application that connects to both a sql server, and a db2
database - so there is a class that provides these connections

helper.getSqlServerConnection();

This helper is initialized by Guice and the connection parameters are
injected from a properties file with @Named.

The problem with this, is that my code is still coupled with the
Connection, so my tests either have to hit a test DB isntance, or the
real DB - neither of which I really want.

My question is, how do I inject this dependency on Connection? Keep
in mind, I need two different Connection's configured just a bit
differently.

Thanks!

Dhanji R. Prasanna

unread,
Nov 2, 2007, 11:20:45 AM11/2/07
to google...@googlegroups.com
I would suggest using a mocking framework like EasyMock for that. If
you're unit testing, then you're probably only interested in a
particular class's (or set of classes) functionality. If it requires a
db connection you can provide it with an EasyMock control and write a
"script" for how it is expected to play with the database.

I sometimes bind these scripted mocks in anonymous Guice modules in
the test, but if I'm just testing a single class I typically create it
by hand and pass the mock in avoiding Guice altogether.

import static org.easymock.EasyMock.*;
//...

Connection mock = createMock(Connection.class);

expect(mock.prepareStatement("...")).andReturn(...); //prepare mock script
replay(mock);

//now begins the test...
MyDao dao = new MyDaoImpl(mock);

//assert various things against my dao

//finally assert script was followed
verify(mock);


Dhanji.

Adam Schaible

unread,
Nov 2, 2007, 11:53:09 AM11/2/07
to google-guice
Dhanji,

Thanks, I appreciate it - I was thinking about that route, but
wasn't sure if there was simply a better way to inject a connection.

On Nov 2, 11:20 am, "Dhanji R. Prasanna" <dha...@gmail.com> wrote:
> I would suggest using a mocking framework like EasyMock for that. If
> you're unit testing, then you're probably only interested in a
> particular class's (or set of classes) functionality. If it requires a
> db connection you can provide it with an EasyMock control and write a
> "script" for how it is expected to play with the database.
>
> I sometimes bind these scripted mocks in anonymous Guice modules in
> the test, but if I'm just testing a single class I typically create it
> by hand and pass the mock in avoiding Guice altogether.
>
> import static org.easymock.EasyMock.*;
> //...
>
> Connection mock = createMock(Connection.class);
>
> expect(mock.prepareStatement("...")).andReturn(...); //prepare mock script
> replay(mock);
>
> //now begins the test...
> MyDao dao = new MyDaoImpl(mock);
>
> //assert various things against my dao
>
> //finally assert script was followed
> verify(mock);
>
> Dhanji.
>

> On 11/2/07, Adam Schaible <adam.schai...@gmail.com> wrote:
>
>
>
>
>
> > Hello everyone,
>
> > Thanks again, in advance -
>
> > I'm pulling the never-ending thread discussed in the user's guide, and
> > I noticed yet another place where my code could be refactored.
>
> > I have an application that connects to both a sql server, and a db2
> > database - so there is a class that provides these connections
>
> > helper.getSqlServerConnection();
>
> > This helper is initialized by Guice and the connection parameters are
> > injected from a properties file with @Named.
>
> > The problem with this, is that my code is still coupled with the
> > Connection, so my tests either have to hit a test DB isntance, or the
> > real DB - neither of which I really want.
>
> > My question is, how do I inject this dependency on Connection? Keep
> > in mind, I need two different Connection's configured just a bit
> > differently.
>

> > Thanks!- Hide quoted text -
>
> - Show quoted text -

Eric Anderson

unread,
Nov 2, 2007, 4:30:39 PM11/2/07
to google...@googlegroups.com
+1 for EasyMock

On 11/2/07, Adam Schaible <adam.s...@gmail.com> wrote:

Brian Slesinsky

unread,
Nov 2, 2007, 11:55:41 PM11/2/07
to google...@googlegroups.com
EasyMock is a great tool, but you won't get much confidence that
you're talking to the database correctly by using it. Any
misunderstanding (for example, bad SQL syntax) is likely to be
duplicated in both the code and the tests, so I still think it's
important to test the database layer against a real database. Of
course you can mock it out when you're testing upper layers, but
whatever interface you define for your database layer is likely to be
more suitable for mocking than java.sql.Connection.

I haven't tried it, but you might also want to consider Mayfly, which
is an in-memory database specifically for testing:

http://mayfly.sourceforge.net/

But then, that doesn't answer your question, because you still have to
inject whatever kind of connection you choose. You might want to try
something like this:

@Inject
Foo(@FirstDbKind Provider<Connection> firstConnectionProvider,
@SecondDbKind Provider<Connection> secondConnectionProvider) {
...
}

Or alternately, inject two instances of javax.sql.DataSource.

- Brian

On 11/2/07, Adam Schaible <adam.s...@gmail.com> wrote:
>

Dhanji R. Prasanna

unread,
Nov 3, 2007, 12:06:04 AM11/3/07
to google...@googlegroups.com
On 11/3/07, Brian Slesinsky <bsles...@gmail.com> wrote:
>
> I haven't tried it, but you might also want to consider Mayfly, which
> is an in-memory database specifically for testing:
>
> http://mayfly.sourceforge.net/

I agree with you in principle, mocked-integration tests are important.
However how do you account for the fact that SQL dialect and behavior
varies between vendors? I use hypersonic (another in-memory db that
ships with Hibernate) to do some basic integration-style tests.
But I know they don't give me any sort of real confidence that the
same code will work against another vendor. I think in these cases a
"proper" stack integration test is warranted for each implementation
stream (db2, sqlserver..).

OTOH testing that the client code is issuing the correct calls to
abstraction API is as simple as a unit test with mocked services.

Dhanji.

Eric Anderson

unread,
Nov 4, 2007, 1:36:39 AM11/4/07
to google...@googlegroups.com
Brian's comment has reminded me of the pains of my current legacy code base and where I would like things to be.  Right now, we have business rules mixed in with persistence in our DAO layer.  What this means is that, in order to test the business rules with unit tests, we have to deal with mocked connections and whatnot.  Blech!

The better way to do this would be to have persistence completely separate from the business rules.  At that point, there is little confidence to be gained in testing the persistence layer with unit tests.  Our goal is to get to a point where all business logic has been removed from the DAO layer (after getting things under test), and then replacing all DAO unit tests with integration level tests that talk to a real, live test database.  Also at that point, the DAO's can be switched out with a better persistence layer that we don't have to touch or test.

Eric

Dhanji R. Prasanna

unread,
Nov 4, 2007, 3:58:00 AM11/4/07
to google...@googlegroups.com
On 11/4/07, Eric Anderson <d.eric....@gmail.com> wrote:
>
> The better way to do this would be to have persistence completely separate
> from the business rules. At that point, there is little confidence to be
> gained in testing the persistence layer with unit tests. Our goal is to get
> to a point where all business logic has been removed from the DAO layer
> (after getting things under test), and then replacing all DAO unit tests
> with integration level tests that talk to a real, live test database. Also
> at that point, the DAO's can be switched out with a better persistence layer
> that we don't have to touch or test.

aka warp-persist ;)

Dhanji.

Brian Slesinsky

unread,
Nov 4, 2007, 3:32:59 PM11/4/07
to google...@googlegroups.com
On 11/3/07, Eric Anderson <d.eric....@gmail.com> wrote:

> The better way to do this would be to have persistence completely separate
> from the business rules. At that point, there is little confidence to be
> gained in testing the persistence layer with unit tests. Our goal is to get
> to a point where all business logic has been removed from the DAO layer
> (after getting things under test), and then replacing all DAO unit tests
> with integration level tests that talk to a real, live test database.

You still need unit tests that show that whatever persistence layer
you choose works with the flavor of database software you're using.
In practice, maybe you're using a persistence layer such as Hibernate,
and it has some unit tests for each database it supports, so you don't
have to write them yourself. But they're still there. It might be a
good idea to run Hibernate's unit tests to make sure that there are no
bugs caused by using a slightly different database configuration than
the Hibernate developers, and even to review their unit tests to see
whether they cover the use cases you're interested in.

- Brian

Reply all
Reply to author
Forward
0 new messages