Self-Contained Testing Using an In-Memory Database

1. Overview

In this tutorial, we’re going to create a simple Spring application which relies on an in-memory database for testing.

For the standard profile, the application will have a standalone MySQL database configuration, which requires having the MySQL server installed and running, with a proper user and database set up.

To make testing the application easier, we will forego the additional configuration required by MySQL and instead use an H2 in-memory database for running the JUnit tests.

2. Maven Dependencies

For development, we need the following dependencies:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.3.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>1.11.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.194</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.2.9.Final</version>
</dependency>

The latest versions of spring-test, spring-data-jpa, h2 and hibernate-entitymanager can be downloaded from Maven Central.

3. Data Model and Repository

Let’s create a simple Student class that will be marked as an entity:

@Entity
public class Student {

    @Id
    private long id;

    private String name;

    // standard constructor, getters, setters
}

Next, let’s create a repository interface based on Spring Data JPA:

public interface StudentRepository extends JpaRepository<Student, Long> {
}

This will enable Spring to create the support for manipulating Student objects.

4. Separate Property Sources

To allow the use of different database configurations for standard mode and testing mode, we can read the database properties from a file whose location is different depending on the running mode of the application.

For normal mode, the properties file will reside in src/main/resources, and for the testing method, we will use a properties file in the src/test/resources folder.

When running a test, the application will first look for files in the src/test/resources folder. If the file is not found in this location, then it will use the one defined in src/main/resources folder. If the file is present is the test path, then it will override the one from the main path.

4.1. Defining the Property Files

Let’s create a persistence-student.properties file in the src/main/resources folder that defines properties for a MySQL data source:

dbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/myDb
jdbc.user=tutorialuser
jdbc.pass=tutorialpass

hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.hbm2ddl.auto=create-drop

In the case of the above configuration, we will need to have the myDb database created and the tutorialuser/tutorialpass user set up.

Since we want to use an in-memory database for testing, we will create a similar file with the same name in the src/test/resources folder, containing properties with the same keys and H2 database-specific values:

jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1

hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create

We have configured the H2 database to live in-memory and be created automatically, then closed and dropped when the JVM exits.

4.2. JPA Configuration

Let’s create a @Configuration class that searches for a file called persistence-student.properties as a property source and creates a DataSource using the database properties defined within it:

@Configuration
@EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao")
@PropertySource("persistence-student.properties")
@EnableTransactionManagement
public class StudentJpaConfig {

    @Autowired
    private Environment env;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.user"));
        dataSource.setPassword(env.getProperty("jdbc.pass"));

        return dataSource;
    }

    // configure entityManagerFactory

    // configure transactionManager

    // configure additional Hibernate Properties
}

5. Creating a JUnit Test

Let’s write a simple JUnit test based on the configuration described above that uses the StudentRepository to save and retrieve a Student entity:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  classes = { StudentJpaConfig.class },
  loader = AnnotationConfigContextLoader.class)
@Transactional
public class InMemoryDBTest {

    @Resource
    private StudentRepository studentRepository;

    @Test
    public void givenStudent_whenSave_thenGetOk() {
        Student student = new Student(1, "john");
        studentRepository.save(student);

        Student student2 = studentRepository.findOne(1);
        assertEquals("john", student2.getName());
    }
}

Our test will run in an entirely self-contained manner — it will create an in-memory H2 database, execute statements, then close the connection and drop the database, as we can see in the log:

INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Hibernate: drop table Student if exists
Hibernate: create table Student (id bigint not null, name varchar(255), primary key (id))
Mar 24, 2017 12:41:51 PM org.hibernate.tool.schema.internal.SchemaCreatorImpl applyImportSources
INFO: HHH000476: Executing import script 'org.hiber[email protected]1b8f9e2'
Hibernate: select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from Student student0_ where student0_.id=?
Hibernate: drop table Student if exists

6. Conclusion

In this quick example, we’ve shown how we can run a self-contained test using an in-memory database.

As always, the full source code can be found over on GitHub.

Leave a Reply

Your email address will not be published.