Using DbUnit Data Sets in Our Integration Tests
After we have finished this lesson, we:
- Know how we can initialize our database into a known state before our integration tests are run.
- Understand how we can write assertions for the data found from our database.
This lesson assumes that:
Specifying the Location of the Used DbUnit Data Set
We can specify the location of a DbUnit data set by following these two rules:
- If the data set is in the same package as the integration test class, we can specify its location by using the file name of the data set.
- If the data set is not in the same package as the integration test class, we can specify its location by using the full path of the data set.
For example, if the name of our data set file is data-set.xml, we can specify its location by following these rules:
- If the data set is in the same package as our integration test class, we can specify its location by using the string: ‘data-set.xml’.
- If the data set is not in the same package as our integration test class and the package of the data set is
com.testwithspring.integrationtest, we can specify its location by using the string: ‘/com/testwithspring/integrationtest/data-set.xml’.
Next, we will find out how we can specify the DbUnit data set that is used to insert test data into our database.
Inserting Test Data Into Our Database
When we configure the DbUnit data set that initializes our database into a known state, we have to use one of these three options:
First, if all test methods of our test class use the same data set, we can specify the used DbUnit data set by annotating our test class with the @DatabaseSetup annotation.
For example, if we want to use a DbUnit data set that is not found from the same package as our test class and the package of our data set is com.testwithspring.integrationtest, the source code of our test class looks as follows:
1@DatabaseSetup("/com/testwithspring/integrationtest/messages.xml")
2public class IntegrationTest {
3
4 @Test
5 public void shouldDoX() {
6
7 }
8
9 @Test
10 public void shouldDoY() {
11
12 }
13}
Second, if every test method of our test class use a different data set, we have to specify the used DbUnit data sets by annotating our test methods with the @DatabaseSetup annotation.
For example, if we want to use DbUnit data sets that are found from the same package as our test class, the source code of our test class looks as follows:
1public class IntegrationTest {
2
3 @Test
4 @DatabaseSetup("messages-x.xml")
5 public void shouldDoX() {
6
7 }
8
9 @Test
10 @DatabaseSetup("messages-y.xml")
11 public void shouldDoY() {
12
13 }
14}
Third, if we want to use multiple DbUnit data sets, we can configure multiple data sets by using the @DatabaseSetup annotation.
For example, if all test methods of our test class use the same DbUnit data sets and these data sets are in the same package as our test class, the source code of our test class looks as follows:
1@DatabaseSetup({
2 "messages-1.xml",
3 "messages-2.xml"
4})
5public class IntegrationTest {
6
7 @Test
8 public void shouldDoX() {
9
10 }
11
12 @Test
13 public void shouldDoY() {
14
15 }
16}
If we use multiple data sets, DbUnit processes these data sets by using the order in which we specified them. In other words, our data sets are processed in this order:
- messages-1.xml
- messages-2.xml
@DatabaseSetup annotation.
Also, if we don’t specify the DatabaseOperation that is used to initialize our database, Spring Test DbUnit uses its default behavior that performs the following operations:
- It deletes all rows from the database tables found from our DbUnit data sets.
- It inserts the test data into our database.
Even though the default behavior is suitable for most use cases, we can configure the used DatabaseOperation by specifying the value of the @DatabaseSetup annotation’s type attribute.
For example, if we want to use the DatabaseOperation.UPDATE, the source code of our test class looks as follows:
1@DatabaseSetup(value = "messages.xml", type = DatabaseOperation.UPDATE)
2public class IntegrationTest {
3
4 @Test
5 public void shouldDoX() {
6
7 }
8
9 @Test
10 public void shouldDoY() {
11
12 }
13}
Additional Reading:
Let’s move on and find out how we can write assertions for the data found from our database.
Writing Assertions for the Data Found From Our Database
When we want to write assertions for the data found from our database, we have to annotate our test method with the @ExpectedDatabase annotation. When we use this annotation, typically we have to specify the values of these two attributes:
- The
valueattribute specifies the location of our DbUnit data set. - The
assertionModeattribute specifies the used assertion mode.
Let’s take a look at two examples that demonstrate how we can use these attributes.
First, we can specify the location of the used data set by following the rules that we described in the beginning of this lesson.
For example, if we want to use two different data sets, the source code of our integration test class looks as follows:
1public class IntegrationTest {
2
3 @Test
4 @ExpectedDatabase("integration-test-should-do-x-expected.xml")
5 public void shouldDoX() {
6
7 }
8
9 @Test
10 @ExpectedDatabase("integration-test-should-do-y-expected.xml")
11 public void shouldDoY() {
12
13 }
14}
When we create and specify our DbUnit data sets, we should follow these three rules:
- We should use small data sets that assert one logical concept.
- We should put our data sets to the same package as our integration test class.
- We should name our data set files by using this naming convention: [name of our test case]-[expected outcome]-expected.xml.
Second, we must not use the default assertion mode because it verifies the content of the entire database. If we use this assertion mode, our data sets are so big that they are unreadable. This means that we have to use one of these two assertion modes:
- The
DatabaseAssertionMode.NON_STRICTallows us to create data sets that contain only specific tables and table columns. If we use this assertion mode, DbUnit ignores unspecified tables and columns. - The
DatabaseAssertionMode.NON_STRICT_UNORDEREDis an extension of theDatabaseAssertionMode.NON_STRICTthat ignores the order of the database rows found from the expected and actual data sets.
For example, if we want to write an assertion that uses the DatabaseAssertionMode.NON_STRICT, the source code of our integration test class looks as follows:
1public class IntegrationTest {
2
3 @Test
4 @ExpectedDatabase(
5 value = "integration-test-should-do-x-expected.xml",
6 assertionMode = DatabaseAssertionMode.NON_STRICT
7 )
8 public void shouldDoX() {
9
10 }
11}
Additional Reading:
Let’s summarize what we learned from this lesson.
Summary
This lesson has taught us four things:
- If the DbUnit data set is in the same package as our integration test class, we can specify its location by using the file name of the data set.
- If the data set is not in the same package as our integration test class, we can specify its location by using the full path of the data set.
- When we initialize our database into a known state, most of the time we don’t have to override the default
DatabaseOperation. - When we write assertions for the data found from our database, we must not use the default assertion mode.