1. Overview
In this tutorial, we will create a simple Spring application that relies on an in-memory database for testing.
For the standard profile, the application will have a standalone MySQL database configuration, which requires installing and running the MySQL server, 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>6.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.4.2.Final</version>
</dependency>
The latest versions of spring-test, spring-data-jpa, h2 and hibernate-core 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.
The application will first look for files in the src/test/resources folder when running a test. If the file is not found in this location, it will use the one defined in the src/main/resources folder. If the file is present in 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.MySQLDialect
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;NON_KEYWORDS=KEY,VALUE
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 = "com.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.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@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 on GitHub.