Baza w pamięci i testach

A teraz najciekawsze. Podczas testowania kodu Hibernate bardzo często chcesz pracować nie z prawdziwą bazą, ale z jakimś kodem pośredniczącym, który implementuje minimalną funkcjonalność.

Czy możesz sobie wyobrazić kod pośredniczący, który implementuje większość standardu SQL Server? Ja nie. Jednak bazy danych w pamięci są doskonałe jako takie. Działa to mniej więcej tak:

  • W metodzie @BeforeAll inicjujemy połączenie z bazą danych w pamięci.
  • W metodzie @BeforeEach pobieramy sesję i otwieramy transakcję.
  • W metodzie @Test pracujemy z bieżącą sesją i transakcją.
  • W metodzie @AfterEach zatwierdzamy transakcję.
  • I na koniec w metodzie AfterAll zamykamy połączenie z bazą danych.

Oto jak wygląda przygotowanie do egzaminu:

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

A tak wygląda sam test z pracą 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());
  }
}

dane testowe

Możesz także wypełnić swoją testową bazę danych danymi testowymi.

Zwykle tworzone są w tym celu dwa pliki sql:

  • schema.sql zawiera skrypt, który tworzy tabele w bazie danych
  • test-data.sql zawiera skrypt, który wypełnia tabele danymi testowymi

Tworzenie tabeli i dane testowe są zwykle rozdzielone na różne pliki, ponieważ prawie zawsze pojawiają się ich własne grupy danych testowych dla różnych grup testowych.

Wykonanie tych plików wygląda następująco:

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

Twoja metoda konfiguracji nieco się zmieni:

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