Base i hukommelse og test

Og nu det mest interessante. Når du tester Hibernate-kode, vil du meget ofte ikke arbejde med en rigtig base, men med en slags stub, der implementerer minimal funktionalitet.

Kan du forestille dig en stub, der implementerer det meste af SQL Server-standarden? Mig ikke. In-memory-databaser er dog fremragende som sådan. Det fungerer nogenlunde sådan her:

  • I @BeforeAll-metoden initialiserer vi databaseforbindelsen i hukommelsen.
  • I @BeforeEach-metoden får vi sessionen og åbner en transaktion.
  • I @Test-metoden arbejder vi med den aktuelle session og transaktion.
  • I @AfterEach-metoden forpligter vi transaktionen.
  • Og til sidst, i AfterAll-metoden, lukker vi forbindelsen til databasen.

Sådan ser forberedelsen til testen ud:

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

Og sådan ser selve testen ud med arbejdet med 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());
  }
}

testdata

Du kan også udfylde din testdatabase med testdata.

Normalt laves to sql-filer til dette:

  • schema.sql indeholder et script, der opretter tabeller i databasen
  • test-data.sql indeholder et script, der udfylder tabeller med testdata

Tabeloprettelse og testdata er normalt opdelt i forskellige filer, da deres egne grupper af testdata for forskellige testgrupper næsten altid vises.

Udførelse af disse filer ser sådan ud:

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

Og din opsætningsmetode vil ændre sig en smule:

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