База в памяти и тестирование

А теперь самое интересное. При тестировании кода Hibernate очень часто хочется работать не с реальной базой, а с какой-нибудь заглушкой, реализующей минимальную функциональность.

А ты представляешь заглушку, которая реализует большую часть стандарта SQL-сервера? Я — нет. Однако в качестве такой отлично подходят базы данных в памяти. Работает это примерно по такой схеме:

  • В методе @BeforeAll мы инициализируем соединение с базой данных в памяти.
  • В методе @BeforeEach мы получаем сессию и открываем транзакцию.
  • В методе @Test мы работаем с текущей сессией и транзакцией.
  • В методе @AfterEach мы комитим транзакцию.
  • И наконец в методе AfterAll мы закрываем соединение с базой.

Вот как выглядит подготовка к работе теста:


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

А вот так выглядит сам тест с работой 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());
  }
}

Тестовые данные

Также ты можешь заполнить свою тестовую базу тестовыми данными.

Обычно для этого делают два sql-файла:

  • schema.sql содержит скрипт, который создает таблицы в базе
  • test-data.sql содержит скрипт, который заполняет таблицы тестовыми данными

Создание таблицы и тестовые данные обычно разносят по разным файлам, так как практически всегда появляются свои группы тестовых данных для разных групп тестов.

Выполнение этих файлов выглядит так:


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

И твой метод setup немного изменится:


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

Пишем свой Hibernate

Код проекта