Showing posts with label TDD. Show all posts
Showing posts with label TDD. Show all posts

Thursday, August 9, 2007

EasyMock Class Extension 2.2 Gotcha

EasyMock mocks interfaces, and the Class Extension mocks classes.

When using the class extension, the EasyMock from the org.easymock.classextension package should be used instead of the same-named class from the original org.easymock package.

When working with more than one mocks with Java 5, we can invoke the replay and verify methods using varargs, such as:
import static org.easymock.classextension.EasyMock.*;
...
replay(mockCustomerRepository, mockCustomer);
...
verify(mockCustomerRepository, mockCustomer);
However, if one of the mocks is mocking a class instead of an interface, I got an IllegalArgumentException: not a proxy instance.

Looking into the stack trace, I can see the EasyMock.replay/verify from the original org.easymock package is used instead of the one from org.easymock.classextension package, as stated in the import statement.

What happened is: org.easymock.classextension.EasyMock extends the org.easymock.EasyMock without providing a vararg version of replay(Object...) and verify(Object...) method. Thus, when the vararg versions are invoked, the control is passed to the vararg version of its super class, which only mocks interfaces using standard Java Proxy.

To get around this, you invoke the single parameter version, such as:
import static org.easymock.classextension.EasyMock.*;
...
replay(mockCustomerRepository);
replay(mockCustomer);
...
verify(mockCustomerRepository);
verify(mockCustomer);
Of course, this gotcha only exists in EasyMock class extension 2.2. The latest 2.2.2 version provides vararg version for these two methods. So a better solution is to upgrade to this latest version.

Tuesday, July 31, 2007

Handling referential integrity when doing persistence testing using DbUnit

DbUnit is a great tool when testing database persistence codes.

There are many ways to using DbUnit. Anyhow, my preferred way is to delete all records from the database tables and re-populate with test data before each test. For unit testing, I test against a memory database, such as Hypersonic; for integration testing, I test against a database that mirrors the one in production.

However, this approach sometimes will get you into the trouble of referential integrity violation.

For example, I had some integration tests against the PRODUCT table, and later I developd some integration tests against the ORDER table, which has a foreign key dependency on the PRODUCT table.

After checking in the latest changes, the continuous integration test failed because of data integrity violation. The cause was that the PRODUCT integration tests saved some records in both PRODUCT and ORDER table, with some orders referencing some products. When DbUnit tried to delete all records from the PRODUCT table, the database detected the violation.

How to solve this? It's pretty easy, just add an empty ORDER record to the test data XML file that is used to populate the database. Following is a sample of a FlatXmlDataSet file:

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<product id="1" desc="abc" price="1.23"/>
<order/>
</dataset>
The trick is that in a FlatXmlDataSet file, the order of the tables defined must follow the dependency, that is, a later defined table can have a dependency on an earlier defined table. When DbUnit deletes records, it will delete records from the last defined table first.