Spring Integration Testing with Spock Mocks
April 18th, 2017
How to inject Spock mocks into the Spring Context during integration tests.
MariaDB4j is an embedded Java wrapper for spinning up a MariaDB instance for local development or continuous integration testing purposes. Using an embedded (or in-memory) database is extremely beneficial when developing a Java application. Traditional embedded DB options are H2, HSQLDB, and Derby. MariaDB4j provides a local DB perfect for a project that deploys to MySQL or MariaDB in production.
First a quick aside, if you are unfamiliar with MariaDB — it was built by the original developers of MySQL as a completely open source successor. MariaDB is billed as a Drop In replacement for MySQL.
A few reasons. To have a full application database for local development. To spin up a separate clean DB for integration testing. Easy setup — no need for each developer to maintain local database servers. It provides the convenience of being able to develop an app completely off-network; it eliminates the need to connect to a shared development database.
We started our Spring Boot project using the default H2 database. It is very fast, and usually what I prefer. However our project had a large amount of complex Flyway SQL Database Migration scripts that were written by our DBA for use on the dev/staging/prod MariaDB database. At first we started to manually modify the SQL to work in a DB-agnostic fashion, but this was very time consuming and tedious. So we toyed with the idea of running a local DB inside a Docker container. Neither was as easy as running an embedded database, so after some searching we found MariaDB4j.
MariaDB4j can be used in any JVM environment (java, groovy, kotlin, etc…), and it has a nice convenience wrapper for Spring. On startup of your application it will install a DB instance in a tmp folder and start it. Depending on your configuration — on shutdown it can leave the DB persistent on disk, or you can tell it to destroy the DB.
Just add the following to your Gradle file (or use the Maven equivalent): compile “ch.vorburger.mariaDB4j:mariaDB4j:2.2.3”
The config here can be used for Local and Integration Tests, and is switched on using Spring Profiles. You’ll need a separate PersistenceConfig running under a normal profile for dev/staging/prod that wires up your normal LocalContainerEntityManagerFactoryBean configuration.
import ch.vorburger.mariadb4j.DBConfigurationBuilder
import ch.vorburger.mariadb4j.springframework.MariaDB4jSpringService
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile
import javax.sql.DataSource
@Configuration
@Profile(['local', 'integrationTest'])
class EmbeddedMariaDbConfig {
@Bean
MariaDB4jSpringService mariaDB4jSpringService() {
new MariaDB4jSpringService()
}
@Bean
DataSource dataSource(MariaDB4jSpringService mariaDB4jSpringService,
@Value('${app.mariaDB4j.databaseName}') String databaseName,
@Value('${spring.datasource.username}') String datasourceUsername,
@Value('${spring.datasource.password}') String datasourcePassword,
@Value('${spring.datasource.driver-class-name}') String datasourceDriver) {
//Create our database with default root user and no password
mariaDB4jSpringService.getDB().createDB(databaseName)
DBConfigurationBuilder config = mariaDB4jSpringService.getConfiguration()
DataSourceBuilder
.create()
.username(datasourceUsername)
.password(datasourcePassword)
.url(config.getURL(databaseName))
.driverClassName(datasourceDriver)
.build();
}
}
And some sample properties files, one for local development running on the same port every time, and data persistent to the file system. And the other for integrationTests that picks a random port and is stored in the tmp directories.
#Location of db files. delete this directory if you need to recreate from scratch
mariaDB4j.dataDir=./data/local
#Default is 3306, so using 3307 just in case it is already running on this machine
mariaDB4j.port=3307
app.mariaDB4j.databaseName=app_alpha
spring.datasource.url=jdbc:mariadb://localhost:3307/
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
#Setting to blank will put db into a tmp directory and recreate every test run
mariaDB4j.dataDir=
#Pick a random open port
mariaDB4j.port=0
Hopefully this helps you run MariaDB4j on your own project. Let me know if you have any issues. The maintainers of MariaDB4j are very receptive to comments and feedback, and have a very welcoming community, so you can also reach out to their github page for more info. All the code here is published on a Github Gist.
Jeff has developed Java, Groovy, Grails, and Javascript web apps for industries as varied as Defense, Energy, Weather, Insurance, and Telecom. He is a co-organizer of the Omaha Java Users Group. Jeff has worked on Grails projects since the Grails 1.3.x days, and has experience with production Groovy code as well as Spock tests and Gradle builds. His latest focus has been on AngularJS and Spring Boot applications using JHipster. Jeff also enjoys volunteering at local CoderDojo events to teach programming to our next generation.