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);
}
}