As agile penetrates into the enterprise more focus will be put on automated integration testing. Since many interactions with a domain require data in a constant state lets explore how to preload a local data store while running in spring context.
Detailed Video Notes
Much of the code you write can be tested using mocking frameworks such as mockito or easy mock but there is certain instances where you want to execute code and validate behavior against a database. It is important when running integration and functional tests that the database is in a known state before every test in order to have reproducible tests without side effects. Prior to Spring 4.1 if you were looking for your domains to interact with a database you could seed data with a tool like DBUnit prior to ApplicationContext
loading but it was fairly intensive. In this tutorial lets find out how spring's testing improvements has simplified executing SQL scripts and inserting test data into an embedded database.
Project set up
[0:38]
Setting up a spring boot project through the starter initializer selecting spring-boot-starter-jdbc
and spring-boot-starter-web
we will generate and download a maven project that we will import into eclipse. Next adding the hyper SQL dependency will allow us to connect and interact with an embedded database.
Configure embedded database with boot
[0:56]
You are probably thinking we need to configure the database url, username, password and driver class. Luckily spring boot will recognize HSQLDB classes on the classpath and will autoconfigure an embedded database which saves us some work! If you are interested in the lower level classes that make that happen look at EmbeddedDatabaseConnection and EmbeddedDataSourceConfiguration.
If you want to connect to an external datasource such as oracle or mysql you can specify spring.datasource.*
in application.properties or application.yml.
Walking through test class
[1:17]
Let's explore the ApplicationTests
class that the initializer created for us. First the @RunWith(SpringJUnit4ClassRunner.class)
states instead of using the default junitrunner use SpringJUnit4ClassRunner instead. Next the @SpringApplicationConfiguration
will load a javaconfig class to configure the ApplicationContext. Our configuration is light but this is where you could include multiple configuration classes to set up your tests. Last is @WebAppConfiguration
which just says to load it with a WebApplicationContext
which has some underlying behavior. Let's run the default test to validate that the set up is functional thus far.
Creating scripts
[1:50]
Next we will create two scripts. The first script will contain sql statements to create a table named PERSON
and an insert statement to load "Fred".
The second script will be executed after tests and will drop the PERSON
table.
Exploring @Sql and @SqlGroup
[2:2]
As mentioned we want to execute the beforeTestRun.sql
prior to any tests running and afterTestRun.sql
after each test method has executed. We can do this by using the @Sql
and @SqlGroup
. The @Sql
annotation can be declared on a test class or test method and allows you to specify a file to be executed against the database. The default behavior is to run it before every test but if we want to be explicit we can add
.executionPhase = ExecutionPhase.BEFORE_TEST_METHOD
Next we want to execute our second script. Since we are running prior to java 8 we need to use the @SqlGroup
to declare multiple instances of @Sql
otherwise we could take advantage of the repeating annotations. Let's wrap our first statement with @SqlGroup
and add our second @Sql
annotation. You will notice we included
so that this script will be execute after each test.executionPhase = ExecutionPhase.AFTER_TEST_METHOD
Executing the class and viewing the logs we can see the scripts being executed.
Writing a query to validate
[3:0]
To validate the code lets write a simple query and use JdbcTemplate
to execute.
Output
You can see @Sql
and @SqlGroup
help simplify populating your database when your application starts and throw away changes when test end. If you are extracting DDL or SQL from an existing source there might be compatibility issues running against an embedded database such as h2 or a derby database. As your tests grow pay attention on how long it is taking scripts to execute in your continuous integration environment to keep builds running fast.
Thanks for joining today's level up, have a great day!