Bas i minne och testning

Och nu det mest intressanta. När du testar Hibernate-kod vill du ofta inte arbeta med en riktig bas, utan med någon form av stubb som implementerar minimal funktionalitet.

Kan du föreställa dig en stubb som implementerar det mesta av SQL Server-standarden? Jag inte. Men minnesdatabaser är utmärkta som sådana. Det fungerar ungefär så här:

  • I @BeforeAll-metoden initierar vi databasanslutningen i minnet.
  • I @BeforeEach-metoden får vi sessionen och öppnar en transaktion.
  • I @Test-metoden arbetar vi med aktuell session och transaktion.
  • I @AfterEach-metoden genomför vi transaktionen.
  • Och slutligen, i AfterAll-metoden, stänger vi anslutningen till databasen.

Så här ser förberedelserna för provet ut:

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

Och så här ser själva testet ut med Hibernates arbete:

@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 också fylla din testdatabas med testdata.

Vanligtvis skapas två sql-filer för detta:

  • schema.sql innehåller ett skript som skapar tabeller i databasen
  • test-data.sql innehåller ett skript som fyller tabeller med testdata

Tabellskapande och testdata separeras vanligtvis i olika filer, eftersom deras egna grupper av testdata för olika testgrupper nästan alltid visas.

Att köra dessa filer ser ut så här:

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

Och din inställningsmetod kommer att ändras lite:

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