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
Setting up a spring boot project through the starter initializer selecting
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
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
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.
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
Exploring @Sql and @SqlGroup
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 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
To validate the code lets write a simple query and use
JdbcTemplate to execute.
You can see
@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!