views:

740

answers:

6

I'm writing tests for a business method that invokes some DAO classes to perform operations over a database.

This method, firstly retrieves a JDBC connection from a DataSource object, The same connection is passed to all DAO instances, so I can use it to control the transaction. So, if everything works properly, I must invoke commit() over the connection object.

I would like to test if the commit() is invoked, so I've thought to create an expectation (I'm using JMock) that checks that. But since the Connection class isn't a direct neighbour from my Business class, I don't know how to do this.

Someone knows how to overcome this? There is some JMock facility for this, or some alternative design that allows to overcome this?

Thanks

+2  A: 

You need to mock DataSource and Connection so that your mock DataSource returns your mock Connection. And yes, this kind of thing ends up becoming a real pain...

Jon Skeet
+3  A: 

It's hard for me to tell from your description exactly how your classes are composed, but the DataSource should be injected into your DAO class, either thru it's constructor or a setDataSource() method.

This would allow you to test the DAO in isolation, and allow you to construct the mock DataSource in your unit test and pass it to the DAO being tested.

matt b
A: 

Make the bussines class retrieve the local variables from a global/static object factory. That way you could put the factory in test mode and make it return mock objects instead of real ones.

That should make it.

argatxa
+1  A: 

Refactor so that the Connection is injected into the Dao and the Dao injected into the business class. You can then mock the Dao and / or the Connection. You can easily write your own mock that extends the Connection and overrides connect() to set a boolean that you later retrieve via a method that write such as wasConnectCalled().

Paul Croarkin
+1  A: 

I would definitely recommend that you use spring-jdbc instead of trying to write this kind of code yourself. This will make sure that the connection, statement and resultset are closed correctly. Spring also has excellent transaction management so you simply don't have to worry about this.

For example take a look at this typical update statement using spring-jdbc:

public void updateName(int id, String name) {
    getJdbcTemplate().update(
            "update mytable set name = ? where id = ?", 
            new Object[] {name, new Integer(id)});
}
Jan Kronquist
A: 

@Paul seconded. And once you've split management of the connection out, you can write the rest of the behaviour in a callback that you pass into the thing that owns the connection -- like a UnitOfWork. The connection owner handles the transaction around, and passes the connection to, the UnitOfWork. Transactions in one place -- easy to test, UnitOfWork in another place, tested with a mock connection.

Steve Freeman