Database Rider: How to improve your DB tests
Recently we were looking at examples for testing the data access layer of an application. Today we are going to see a library that will help us to improve these tests: Database Rider. It is mainly based on the DBUnit library and the Arquillian persistence extension.
DBUnit has as the main function to allow us to put the DB in a concrete state, for the correct operation of the JUnit tests, maintaining the isolation between the different tests. And Arquilliam is a testing framework belonging to JBoss for testing EJB components that are executed or interact with a container. This framework makes it easier to perform integration tests.
What we will get with Database Rider that we won’t get with the other two, is simplicity and being able to run them without the need for another add-on with JUnit 5. To begin with we need to add the dependency of Database Rider, the DB, and the configuration of this one. This configuration will be done through the persistence.xml file because Database Rider is intended for the use of an Entity Manager in the tests. Besides, Database Rider has several libraries depending on how we want to use it, we have selected the one designed to be used with JUnit 5 for our examples.
Basically the configuration we do with Database Rider and its use we will have to perform three steps:
- Add the JUnit5 extension @ExtendWith(DBUnitExtension.class).
- Create an instance of EntityManagerProvider that allows the connection with the DB.
- The @DataSet annotation allows the configuration of the libraries.
In the most basic mode of use, we can indicate a YAML file like the one shown below, which allows us to fill the database before the test.
In the most basic mode of use, we can indicate a YAML file like the one shown below, which allows us to fill the database before the test.
book:
- id: 1
name: "Ender's game"
author: "Orson S. Card"
- id: 2
name: "The starts my destination"
author: "Alfred Bester"
- id: 3
name: "Dune"
author: "Frank Herbert"
Below we can see an example of the basic configuration and how the library works based on the assertions we indicated.
The main annotation of @DataSet can be used at the method level as well or we can invoke it every time we are going to do a test by using the @BeforeEach annotation. But depending on it, the result will be different.
The @DataSet annotation allows different configuration options that can help us when preparing the tests and help in their isolation. For example, cleaning the database before and/or after the execution of the test, or if we prefer to execute a SQL script.
All the possible configuration options can be seen here.
In addition, the library will have an annotation with which we will be able to validate the content of the DB once the test has been executed. This annotation is @ExpectedDataSet. Among other things we will be able to:
- Validate the exact columns and content by passing a YAML file with the table content.
- Validate the partial records, indicating some columns that we want to omit.
- Validate the content partially, indicating regular expressions to validate the content.
The content of the YAML files to validate the tests is shown below. In the first one, we can see how the data is correct except for the id column, and in the second one, we use regular expressions to verify the content. An important aspect in the regular expressions is to indicate a dot before the asterisk.
#expectedBooks.yml
book:
- id: 11
name: "Ender's game"
author: "Orson S. Card"
- id: 22
name: "The starts my destination"
author: "Alfred Bester"
- id: 3
name: "Dune"
author: "Frank Herbert"
- id: 33
name: "Foundation"
author: "Isaac Asimov"
#expectedRegExBooks.yml
book:
- id: "regex:\\d+"
name: regex:^Ender's.*
author: "Orson S. Card"
- id: 2
name: regex:.*starts.*
author: Alfred Bester
- id: 3
name: Dune
author: Frank Herbert
- id: 5
name: regex:.*tion$
author: Isaac Asimov
Finally, indicate a couple of errors that can be more or less common:
- java.lang.IllegalStateException: Call instance(‘PU_NAME’) before calling em(): This may indicate that we have not indicated the @ExtendWith or @DataSet annotation.
- NullPointerException when getting the connection: This is due to errors in the persistence.xml file.
With this, we have taken one more step towards unit or integration testing of our applications. If you want you can see all the code here.