Configure In-memory DB to Unit Test Hibernate

Learn to connect to an in-memory database (such as H2 or Hsqldb) from the JUnit 5 unit tests. This will help in writing tests that do not depend on a live database connection.

1.1. Maven Dependency

For demo purposes, we are using the H2 database. You can choose another database of your choice.

Start with importing the latest version of Hsqldb dependency in the application.

<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>2.6.1</version>
    <scope>test</scope>
</dependency>

To use the H2 database, use the following dependency.

<dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>[2.1.212,)</version>

      <scope>test</scope>
</dependency>

If not already imported, import the JUnit 5 dependencies.

<dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.8.1</version>
      <scope>test</scope>
</dependency>
<dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-params</artifactId>
      <version>5.8.1</version>
      <scope>test</scope>
</dependency>
<dependency>
      <groupId>org.junit.platform</groupId>
      <artifactId>junit-platform-suite</artifactId>
      <version>1.8.1</version>
      <scope>test</scope>
</dependency>

2. Setting Up DB Connection Configuration

Now we need to provide the test-specific database connection configuration that will be used by Hibernate in test execution. The config file name we are using is hibernate-test.cfg.xml.

We need to place this file in /test/resources folder.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.hsqldb.jdbc.JDBCDriver</property>
        <property name="hibernate.connection.url">jdbc:hsqldb:mem:test</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        <property name="hibernate.hbm2ddl.auto">create-drop</property>
        <property name="hibernate.current_session_context_class">thread</property>
    </session-factory>
</hibernate-configuration>

For H2, there will be a small change in the connection properties.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.url">jdbc:h2:mem:test</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        <property name="hibernate.hbm2ddl.auto">create-drop</property>
        <property name="hibernate.current_session_context_class">thread</property>
    </session-factory>
</hibernate-configuration>

3. Initializing SessionFactory and Session

It’s time to write and test our configuration.

  • We will initialize the SessionFactory in @BeforeAll annotated method so that it is initialized once per test class.
  • We will initialize the Session in @BeforeEach annotated method so a new session is created for every test.
  • We will add only those entities in the metadata that are required in the tests in a specific test class. For example, in this demo, we are adding EmployeeEntity because we only need this entity in the test.
  • We will commit the transaction in @AfterEach method and, finally, close the session factory in @AfterAll method.

Note that we have configured the hibernate-test.cfg.xml file in the StandardServiceRegistry. If we do not specify its name, the configuration will, by default, load the src/main/resources/hibernate.cfg.xml file.

public class HelloTest {

  private static SessionFactory sessionFactory = null;
  private Session session = null;

  @BeforeAll
  static void setup(){
    try {
      StandardServiceRegistry standardRegistry
          = new StandardServiceRegistryBuilder()
          .configure("hibernate-test.cfg.xml")
          .build();

      Metadata metadata = new MetadataSources(standardRegistry)
          .addAnnotatedClass(EmployeeEntity.class)
          .getMetadataBuilder()
          .build();

      sessionFactory = metadata
          .getSessionFactoryBuilder().build();

    } catch (Throwable ex) {
      throw new ExceptionInInitializerError(ex);
    }
  }

  @BeforeEach
  void setupThis(){
    session = sessionFactory.openSession();
    session.beginTransaction();
  }

  @AfterEach
  void tearThis(){
    session.getTransaction().commit();
  }

  @AfterAll
  static void tear(){
    sessionFactory.close();
  }

  @Test
  void createSessionFactoryWithXML() {
    EmployeeEntity emp = new EmployeeEntity();
    emp.setEmail("demo-user@mail.com");
    emp.setFirstName("demo");
    emp.setLastName("user");

    Assertions.assertNull(emp.getEmployeeId());

    session.persist(emp);

    Assertions.assertNotNull(emp.getEmployeeId());
  }
}

For reference, the EmployeeEntity class is:

@Entity
@Table(name = "Employee", uniqueConstraints = {
    @UniqueConstraint(columnNames = "ID"),
    @UniqueConstraint(columnNames = "EMAIL") })
public class EmployeeEntity implements Serializable {

      @Serial
      private static final long serialVersionUID = -1798070786993154676L;

      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name = "ID", unique = true, nullable = false)
      private Integer employeeId;

      @Column(name = "EMAIL", unique = true, nullable = false, length = 100)
      private String email;

      @Column(name = "FIRST_NAME", nullable = false, length = 100)
      private String firstName;

      @Column(name = "LAST_NAME", nullable = false, length = 100)
      private String lastName;

      //Getters and Setters are hidden for brevity
}

Now test the above code.

4. Demo

Execute the JUnit test in an IDE or using mvn clean test command. It will execute the tests and produce the output in the console.

Notice the logs that will have similar information.

5.8.1HHH10001005: Loaded JDBC driver class: org.h2.Driver
5.8.1HHH10001012: Connecting with JDBC URL [jdbc:h2:mem:test]
5.8.1HHH10001001: Connection properties: {password=****, user=sa}
5.8.1HHH10001003: Autocommit mode: false
5.8.1HHH10001115: Connection pool size: 20 (min=1)
HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Hibernate: 
    
    drop table if exists Employee cascade 

Hibernate: 
    
    create table Employee (
       ID integer generated by default as identity,
        EMAIL varchar(100) not null,
        FIRST_NAME varchar(100) not null,
        LAST_NAME varchar(100) not null,
        primary key (ID)
    )

Hibernate: 
    
    alter table if exists Employee 
       add constraint UK_ardf0f11mfa6tujs3hflthwdv unique (EMAIL)
Hibernate: 
    insert 
    into
        Employee
        (ID, EMAIL, FIRST_NAME, LAST_NAME) 
    values
        (default, ?, ?, ?)

Hibernate: 
    
    drop table if exists Employee cascade 

HHH10001008: Cleaning up connection pool [jdbc:h2:mem:test]
Process finished with exit code 0

That’s all for this quick tutorial about Using In-memory Database With Hibernate for Unit Testing.

Happy Learning !!

Sourcecode on Github

Comments

Subscribe
Notify of
guest
15 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode