Base in memory and testing

And now the most interesting. When testing Hibernate code, very often you want to work not with a real base, but with some kind of stub that implements minimal functionality.

Can you imagine a stub that implements most of the SQL Server standard? Me not. However, in-memory databases are excellent as such. It works roughly like this:

  • In the @BeforeAll method, we initialize the in-memory database connection.
  • In the @BeforeEach method, we get the session and open a transaction.
  • In the @Test method, we work with the current session and transaction.
  • In the @AfterEach method, we commit the transaction.
  • And finally, in the AfterAll method, we close the connection to the database.

Here is what preparation for the test looks like:

@Test
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(Employee.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();
  }

And this is how the test itself looks like with the work of Hibernate:

@Test
public class HelloTest {

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

       Assertions.assertNull(emp.getEmployeeId());
       session.persist(emp);
       Assertions.assertNotNull(emp.getEmployeeId());
  }
}

test data

You can also populate your test database with test data.

Usually two sql files are made for this:

  • schema.sql contains a script that creates tables in the database
  • test-data.sql contains a script that populates tables with test data

Table creation and test data are usually separated into different files, since their own groups of test data for different test groups almost always appear.

Executing these files looks like this:

void runSqlScriptFile(String filePath){
  	String sqlScript = new String( Files.readAllBytes(Paths.get(filePath)) );
  	Session session = sessionFactory.openSession();
      Query query = session.createNativeQuery("BEGIN " + sqlScript + " END;");
      query.executeUpdate()
}

And your setup method will change a bit:

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

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

	sessionFactory = metadata.getSessionFactoryBuilder().build();
	runSqlScriptFile(“scema.sql”);
	runSqlScriptFile(“test-data.sql”);

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