Jakub is a Java EE developer since 2005 and occasionally a project manager, working currently with Iterate AS. He's highly interested in developer productivity (and tools like Maven and AOP/AspectJ), web frameworks, Java portals, testing and performance and works a lot with IBM technologies. A native to Czech Republic, he lives now in Oslo, Norway. Jakub is a DZone MVB and is not an employee of DZone and has posted 155 posts at DZone. You can read more from them at their website. View Full User Profile

DbUnit Express Tips: Setup Simplification, Custom Data File Convention

08.08.2011
| 5374 views |
  • submit to reddit

I’ve recently introduced here DbUnit Express, a wrapper around DbUnit intended to get you started with testing DB-related code in no time, and now I’d like to share two productivity tips: simplifying db tester setup with a parent test and implementing your own convention for data set files, for example one data set per test class.

Define your own convention for data set names, e.g. per-test-class-data-set

By default DbUnit Express expects you to use dataset testData/dbunit-test_data_set.xml. However you might for example prefer each test to have its own data set, named for example <test class name>-test.xml.

The easiest solution without repeating yourself is to create a custom subclass of EmbeddedDbTester overriding its createDefaultDataSet():

public class PerTestDataSetEmbeddedDbTester extends EmbeddedDbTester {
    @Override
    protected IDataSet createDefaultDataSet() throws DatabaseUnitRuntimeException, DataSetException {
		return createDataSetFromFile(getClass().getSimpleName() + "-data.xml");
	}
}

Notice that if the data set cannot be found in the default location, i.e. testData/, then it is searched for on the classpath, so it is perfectly OK to have it next to the test class.

Setup Simplification

When using DbUnit Express with JUnit 4.x, you typically need to do three things in each test class:

public class SpringBookDaoImplTest {

    private EmbeddedDbTester testDb = new EmbeddedDbTester(); // 1

    @Before
    public void setUp() throws Exception {
        testDb.onSetup(); // 2
    }

    @After
    public void tearDown() throws Exception {
        testDb.onTearDown(); // 3
    }

    ...
}

That is lot of repeated coding and the best way to get rid of it is to create an abstract parent class of all your test classes working with DbUnit Express and moving the code there (changing the tester’s visibility to protected, of course):

public abstract class AbstractMyApplicationDbTest {

    protected EmbeddedDbTester testDb = new EmbeddedDbTester(); // 1

    @Before
    public final void setUpDbUnitExpress() throws Exception {
        testDb.onSetup(); // 2
    }

    @After
    public final void tearDownDbUnitExpress() throws Exception {
        testDb.onTearDown(); // 3
    }

    ...
}

 

From http://theholyjava.wordpress.com/2011/08/05/dbunit-express-tips-setup-simplificatio-custom-data-file-convention/

Published at DZone with permission of Jakub Holý, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Xavier Dury replied on Tue, 2011/08/09 - 1:19am

you could use JUnit @Rules to remove your setUp() and tearDown() methods.

Mladen Girazovski replied on Tue, 2011/08/09 - 9:03am

Can you create the whole dataset inside of the tests?

I prefer to have the testdata in the test in non GUI tests, avoids obscure tests and redudancy, similar to this example: http://xunitpatterns.com/Back%20Door%20Manipulation.html
(scroll down to "Example: Back Door Fixture Setup")

Of course, no need for XML in Java, but writing a generic builder ist easy, using it even easier:

		dataSetBuilder.addRow(TABLE_PROJECT).
						addColumn(COL_ID, projectId).
						addColumn(COL_VERSION, version).
						addColumn(COL_NAME, name);


Writing concrete builders that uses the generics builder is not a problem either, so it can be used very simple:

		createDataBuilder()
				.createProject(projectId, name)
				.createPerson(personId, firstName, lastName)
				.cleanInsertTestData();


So, in the end you'd have all you need to know inside of the test while avoiding redundancy and obscure tests at the same time:

	@Test
	public void testFindById() {
		final String firstName = "First";
		final String lastName = "Last";
		final Integer id = 2;

		createDataBuilder()
			.createPerson(id, firstName, lastName)
			.cleanInsertTestData();

		PersonImpl person = em.find(PersonImpl.class, id);

                assertNotNull("person is null", person);
		assertEquals("id", id, person.getId());
		assertEquals("firstName", firstName, person.getFirstName());
		assertEquals("lastName", lastName, person.getLastName());
	}


Refactoring gets easier, too.

Jakub Holý replied on Sat, 2011/09/03 - 11:40am in response to: Mladen Girazovski

Mladen>Well, IDataSet in DbUnit as an interfaceand you can provide any implementation you want. I even have an example of such programatically created data set in SimpleEmbeddedDbTest.testWithReplacementDataFromDataSet().

Xavier> Thanks for the @Rule tip, I've made use of it in the upcomming DbUnit Express 1.3.0.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.