News: Manage test data for integration tests using Spring and DBUnit
Integration testing is an essential part of software development. Integrated tests are dependent on the right data being in place. This is different from unit tests which run in isolation. DBUnit is a tool which inserts data into the database before the integration tests run and removes data after the test. DBunit also provides facility to export data in a database to an XML file which can then be inserted into the database before every test. The combination of Spring and DBUnit provides an elegant mechanism to transparently populate a database with test data. Integration tests can then produce consistent results without any external dependencies - this article shows you how.
- Posted by: Joseph Ottinger
- Posted on: August 15 2007 10:56 EDT
- Why dbunit? by Branden Root on August 15 2007 13:27 EDT
- Re: Manage test data for integration tests using Spring and DBUn by Steve Cresswell on August 15 2007 18:51 EDT
- Re: Manage test data for integration tests using Spring and DBUn by Alexandre Poitras on August 16 2007 04:27 EDT
- The Summer Slump by Steve Cresswell on August 15 2007 19:04 EDT
- Unitils by Maxim Butov on August 16 2007 04:52 EDT
- Appropriate sizes? by Frank Cohen on August 16 2007 11:16 EDT
- Right tool for the right job by paul browne on August 17 2007 05:15 EDT
- Unitils x 2 by Peter Oxenham on August 23 2007 20:16 EDT
- Re: Manage test data for integration tests using Spring and DBUnit by Hans Schwaebli on September 07 2007 07:59 EDT
- Spring and Junit4 by Tony Murphy on October 01 2007 06:06 EDT
- Date functions with DbUnit by Daniel Nowak on July 22 2009 06:57 EDT
Spring already has plenty of classes to do this: AbstractTransactionalDataSourceSpringContextTests and AbstractJpaTests. Why bother adding in another framework?
Spring already has plenty of classes to do this: AbstractTransactionalDataSourceSpringContextTests and AbstractJpaTests. Why bother adding in another framework?As far as I know, spring does not provide a way to manage test data. That is Spring does not provide a way to ensure test data is present in the database. It provides lifecyclt methods such as 'onSetUpInTransaction' and 'onTearDownInTransaction' which can be used to perform tasks such as inserting test data. But Spring does not provide any facility to do the actual task of inserting and deleting the test data. that is what DBUnit is for. Spring provides the lifecycle methods and DBUnit does the actual work of inserting test data. That is what my example uses.
I find dbUnit / Spring's JDBC template useful for basic CRUD testing of Hibernate mappings, but any more than that tends to end up a maintenance headache (Imagine fixing n number of XML documents whenever your schema changes). For anything more complicated than basic CRUD, I rely on the domain objects and persistance layer to create / retrieve the test data. You may still end up refactoring tests when your schema changes but at least you have the IDE to help you.
I find dbUnit / Spring's JDBC template useful for basic CRUD testing of Hibernate mappings, but any more than that tends to end up a maintenance headache (Imagine fixing n number of XML documents whenever your schema changes).Agreed, this is the best solution IMO. This way you only change your test if your actual domain objects need to change. You are thinking in term of testing domain repositories, not in term of datas which makes a lot more sense to me.
For anything more complicated than basic CRUD, I rely on the domain objects and persistance layer to create / retrieve the test data. You may still end up refactoring tests when your schema changes but at least you have the IDE to help you.
Binary files representing test data can be stored in version control system along with the test data. The disadvantage of this approach is this takes up space and they don’t belong in version control systems.So if your test data isn't in version control how do you regression test a tagged release? Binary files take up space? So what? Disk space is cheap and the best version control systems handle binary deltas.
They can be stored in a file server and retrieved using FTP. The Apache commons-net library provides a FTP client which can be incorporated into a java application to retrieve a file from an FTP server. Apache commons-net library provides facility to read data in files on a FTP server into a byte array.Integration tests are slow and complicated enough without downloading test data from an FTP server. Did I speak to soon when complaining that "The Number One Ill of Java" article hit an all time low. Is this what's known as the summer slump?
I'd recommend try Unitils (see http://unitils.sourceforge.net/tutorial.html) first, before writing your own unit tests using spring and dbunit.
DBUnit looks like a good framework for ETL functions in a testing environment. The article does not give guidance on sizing. For example, is DBUnit appropriate for large (terrabyte) test databases? -Frank Cohen http://www.pushtotest.com
I wouldn't want to maintain by hand an XML file with terabytes of data?
I wouldn't want to maintain by hand an XML file with terabytes of data?You can split up your XML files into several files and use DBUnit to insert more than one file.
If inserting large amounts of data, it will be a good idea to use JUnit 4 or TestNG to insert test data only once at start of test suite. Inserting a lot of test data before every single test will take too long to run the tests.
Use DBUnit to export only a subset of relevant data to XML file. This relevant data is unlikely to get to terrabytes in size. Size of my production/live data is about 8 GB and the size of XML file is about 100 kb and it has test data for about 100 tests. Different unit test will very likely have some common test data too.
If the size of your test data is indeed very big, then you have other problems to face as well. Example: Where to store XML file, time taken to insert test data, how to split XML files into smaller files
DBUnit looks like a good framework for ETL functions in a testing environment. The article does not give guidance on sizing. For example, is DBUnit appropriate for large (terrabyte) test databases?As mentioned in the article, inserting test data before each test is inefficient but ensures that the results of a test do not influence any other test. Junit4 and TestNG have a more sophisticated lifecycle and provide other lifecycle methods(e.g. BeforeClass and AfterClass) to insert test data once for each test or once for each test group. So tests will run much faster but any changes to test data by one test will be visible to other tests.
I'm a big fan of DBUnit , but like everything , it's a case of using the right tool for the right job.
- For projects where the schema is small, and you have control over it (e.g. new developments) then DBUnit is an excellent choice. It allows you to blow away and rebuild your database between every test run.
- For project with a large schema with complex or large data sets DBUnit (with it's XML based Schema) can be costly to maintain and run. Fallback then is having a 'real' database with a snapshot of test data. Managing this snapshot and the tests that run against it then becomes the issue.
I agree with Maxim. I created a similar work frame but like some of the posts mention, keeping the XML up to date was a hassle. Unitils has some clever ways to remove that hassle.
We don't use DBUnit for the server side integration tests. The test data is created with the DAOs in the JUnit tests' setup methods: Customer king = new Customer(); king.setName("King"); ... king.persist(); The entities which are persisted are automatically added in a kind of entity garbage collector. In the tear down method the persisted entities are then deleted automatically. This is done by a class we named "EntityGarbageCollector". It has a method to add persisted entities and a method to delete them all. The advantage compared to DBUnit I see in this: 1. It doesn't matter for the serverside integration tests when column names change. 2. Test data are created in the same way the tests are created, by writing them in a JUnit class. It is all done in one place. 3. No knowledge of a additional testing framework like DBUnit is required. But you need some convenience and utility methods. 4. The caching of the application server doesn't need to be manipulated (cache-between-transactions = false, and things like that), because the data are created throuh the application server and it is not bypassed. 5. You automatically test the DAOs by writing business logic tests. And by doing it like this, you can use your validation rules to prevent creating invalid data. If your database or ORM supports rollback, then the performance and quality of the tests can increase if you use this feature.
Works with annotations in junit4 Use AbstractAnnotationAwareTransactionalTests instead of AbstractTransactionalDataSourceSpringContextTests
Works with annotations in junit4sorry, made a mistake Spring and Junit4 but until spring 2.1 Need to annotate test class with @RunWith(JUnit4ClassRunner.class) each test needs @Test
I needed some date functions inside my db unit fixtures, so i patched the the dbunit so, that i am able to write things like: to create a timestamp that is 10 seconds before now. You can download the patch and the patched jar here: http://ruby.jazzanowak.de/date-functions-in-dbunit-fixtures/