Tuesday, July 31, 2007

EasyMock2 quirk...

When using EasyMock 2 for testing, typically we need to set up expectations before replay, like this:
expect(mockEmployeeRepository
.findByFirstNameAndLastName("John", "Doe"))
.andReturn(employees);
Sometimes, you don't know exactly what parameter will be used for the expected call, you can instead specify the class of the parameter, such as:
expect(mockEmployeeRepository
.findBySpecification(isA(EmployeeSearchSpecification.class))
.andReturn(employees);
What if you know the exact value of some but not all parameters? I tried the following:
expect(mockEmployeeRepository
.findByDepartmentAndSpecification("HR",
isA(EmployeeSearchSpecification.class))
.andReturn(emplooyees);
Unfortunately, running this test will get the following exception thrown by EasyMock:
java.lang.IllegalStateException: 2 matchers expected, 1 recorded.
The correct way is to wrap the known parameter with an "eq" matcher:
expect(mockEmployeeRepository
.findByDepartmentAndSpecification(eq("HR"),
isA(EmployeeSearchSpecification.class))
.andReturn(employees);
This is a small quirk when using EasyMock 2.2...

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.

Sunday, July 29, 2007

Springify a "Singleton"-infested application

The singleton pattern has been avidly avoided by most developers since the introduction of Spring, which solved the problem in an elegant way.

However, there have been many applications that were developed before and were infested with the "evil" singleton pattern. Quite often, these singletons are not really singletons; the singleton pattern was just misapplied to a problem that may be more suitable to use Registry to solve.

Every now and then, developers are asked to add Spring to such applications with minimal code changes and refactoring because these applications typically do not have any automated unit tests or do not have a good enough test coverage.

Adding Spring to such applications is rather simple if there is no dependency between the existing codes and the Spring-managed beans.

If Spring-managed beans have a dependency on a "singleton" that is not managed by Spring. We can define the "singleton" as a Spring-managed bean using a "factory-method", such as "getInstance()", to retrieve the "singleton" instance and inject it into other beans.

Things get more complex when you want to use Spring to configure these "singletons".

For example, one of the application that I need to springify used a "singleton" to look up data source from JNDI. In order to add tests that can be run out of container, we need to inject a Spring-configured data source, whether it is registered with JNDI or not, to that "singleton" instance, instead of letting the "singleton" to look up JNDI.

What we did was that we added a new static factory method "createInstance(DataSource)" accepting a pre-configured data source and returning the singleton instance. Then we configure Spring to invoke this new factory method to create a bean, which is stored in the original static variable and returned to caller of the static "getInstance()" method.

I have read on the internet that some call this a "Singleton with a back door" pattern. To me, it is pretty clear that the singleton pattern is misused here. What the original developer really needed was a "Registry" pattern that allows other objects to "find common objects and services" using "a well-known object". Spring creates and configures the common object or service, which is registered so that other objects in the same application can locate it.

In fact, Spring itself uses "Registry" pattern in many places. Some of the significant places include transaction management and JDBC connection management. Spring uses a thread-local scoped registry to hold JDBC connection so that all JDBC operations within the same transaction use the same JDBC connection...

One thing to note when using Spring to configure such "singletons" is that there are typically many implicit dependencies between these "singletons". If Spring instantiates these "singletons" in a wrong order, the application cannot run properly, usually with failure in constructing application context. The solution to this is to use the "depends-on" attribute in bean definition to explicitly specify the dependencies between these "singletons".