在使用测试容器进行集成测试时,您如何管理 EM 或 EMF?

How you manage EM or EMF in integration testing with testcontainers?

我有 java 网络应用程序,我想为服务层编写集成测试。我决定使用 testcontainers,所以在测试中我想调用服务,它将与 docker 容器中的数据库一起工作。

我的测试 class 如下例所示。

@Testcontainers
class ITPlayerServiceImpl {

  @Container
  private static final PostgreSQLContainer POSTGRE_SQL_CONTAINER = 
  new PostgreSQLContainer()
            .withDatabaseName("dbName")
            .withUsername("dbUserName")
            .withPassword("dbPassword");
}

已测试服务。

@Stateless
public class PlayerServiceImpl implements PlayerService {

  @PersistenceContext(unitName = "persistence_unit_name")
  private EntityManager entityManager;

  //Methods

我需要在容器中创建连接到数据库的 EMF,然后将 EM 从该 EMF 填充到测试服务中。

感谢您的帮助或提示。

经过一些调查和测试,我以下面的解决方案结束。

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Testcontainers
class ITApplicationUserService {

    @Container
    private static final PostgreSQLContainer POSTGRE_SQL_CONTAINER = new PostgreSQLContainer()
            .withDatabaseName("someDatabase")
            .withUsername("someUsername")
            .withPassword("somePassword");

    // EMF for integration tests
    private static EntityManagerFactory emf;

    // EM for tested service
    private static EntityManager entityManager;

    // Tested service
    private static ApplicationUserServiceImpl applicationUserService = new ApplicationUserServiceImpl();

    // Object used for testing
    private static ApplicationUser testingApplicationUser;


    @BeforeAll
    static void init() {

        // Properties for our EMF, which will make EM connected to POSTGRE_SQL_CONTAINER
        Map<String,String> properties = new HashMap<>();
        properties.put("javax.persistence.jdbc.url",POSTGRE_SQL_CONTAINER.getJdbcUrl());
        properties.put("javax.persistence.jdbc.user",POSTGRE_SQL_CONTAINER.getUsername());
        properties.put("javax.persistence.jdbc.password",POSTGRE_SQL_CONTAINER.getPassword());
        properties.put("javax.persistence.jdbc.driver",POSTGRE_SQL_CONTAINER.getDriverClassName());
        properties.put("eclipselink.logging.level","FINE");

        // We need create fresh empty schema in POSTGRE_SQL_CONTAINER
        properties.put("javax.persistence.schema-generation.database.action","create");

        // Creation of EMF
        emf = Persistence.createEntityManagerFactory("integrationTesting",properties);

        // Player for testing
        testingApplicationUser = new ApplicationUser();
        testingApplicationUser.setLogin("loginName");
        testingApplicationUser.setEmail("something@somewhere.com");
        testingApplicationUser.setPassword("123456");
    }

    @Test
    @Order(1)
    void saveNewApplicationUserTest() {
        assertTrue(testingApplicationUser.getId()==null);
        ApplicationUser applicationUser = applicationUserService.saveApplicationUser(testingApplicationUser);
        assertTrue(applicationUser.getId()!=null);
    }

    @Test
    @Order(2)
    void getApplicationUsers() {
        assertTrue(applicationUserService.getAllApplicationUsers().size()==1);
    }


    @BeforeEach
    private void startTransaction() throws IllegalAccessException, NoSuchFieldException {
        entityManager = emf.createEntityManager();
        // We will declare field of EM in tested service
        // EM field in tested class is not public and should not be. We will use reflection for population of EM.
        Field emField = applicationUserService.getClass().getDeclaredField("entityManager");
        emField.setAccessible(true);
        emField.set(applicationUserService,entityManager);

        entityManager.getTransaction().begin();
    }

    @AfterEach
    private void commitTransaction() {
        if (entityManager.getTransaction().isActive()) {
            entityManager.getTransaction().commit();
            entityManager.close();
        }

    }

}