我在为 JUnit 设置 H2 数据库时遇到问题。 需要注意的是 - 我没有使用 Spring Boot 自动配置。
我想清除每次测试之间的所有数据。 测试类扩展了用于设置 H2 连接的 H2DatabaseConfig 类。 我的计划是使用 @AfterAll 注释清除所有数据。 我不想使用deleteAll方法,比如完全删除数据(行和自动增量重置)。
此刻, 当我单独运行每个测试时,一切都很好。 但是当我一起运行时,我收到错误
jakarta.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.example.database.entity.Team]
我知道它与我的父类有关。 它与我重新创建会话/连接的方式有关。 但不知道如何解决。
我很感激您提供的任何提示。先谢谢你了
H2数据库配置
public class H2DatabaseConfig {
private static Server server;
private static Connection connection;
protected static EntityManagerFactory entityManagerFactory;
private static EntityManager entityManager;
@BeforeEach
public void setUp() throws SQLException {
server = Server.createTcpServer().start();
connection = DriverManager.getConnection("jdbc:h2:mem:test;MODE=MYSQL", "root", "password");
entityManagerFactory = Persistence.createEntityManagerFactory("entity-manager-test");
entityManager = entityManagerFactory.createEntityManager();
Container.initBeans(entityManager);
}
@AfterEach
public void tearDown() throws SQLException {
connection.close();
server.stop();
}
}
测试类
class FormTeamAddControllerTest extends H2DatabaseConfig {
private FormTeamAddController formTeamAddController;
private TeamSavePort teamSavePort;
@BeforeEach
public void set() {
formTeamAddController = new FormTeamAddController();
teamSavePort = Container.getBean(TeamSavePort.class);
}
@Test
public void shouldSaveTeam() {
// when
ValidatorResponse save = formTeamAddController.save("Lowe", "123");
// then
assertTrue(save.isOk());
assertEquals(TeamInputValidator.msgTeamIsCreated("Lowe"), save.getMessage());
}
@Test
public void shouldNotSaveTeamCauseDuplicateTeamName() {
teamSavePort.save("Star", BigDecimal.valueOf(123));
// when
ValidatorResponse save = formTeamAddController.save("Star", "123");
// then
assertTrue(save.hasErrors());
assertEquals(save.getErrors().get("name"), TeamInputValidator.errTeamNameExists());
}
@Test
public void shouldNotSaveTeamCauseWrongName() {
// when
ValidatorResponse save1 = formTeamAddController.save(null, "123");
ValidatorResponse save2 = formTeamAddController.save(" ", "123");
ValidatorResponse save3 = formTeamAddController.save("", "123");
// then
assertTrue(save1.hasErrors());
assertTrue(save2.hasErrors());
assertTrue(save3.hasErrors());
assertEquals(save1.getErrors().get("name"), TeamInputValidator.errTeamName());
assertEquals(save2.getErrors().get("name"), TeamInputValidator.errTeamName());
assertEquals(save3.getErrors().get("name"), TeamInputValidator.errTeamName());
}
@Test
public void shouldNotSaveTeamCauseWrongMembershipFee() {
// when
ValidatorResponse save1 = formTeamAddController.save("Star", null);
ValidatorResponse save2 = formTeamAddController.save("Star", " ");
ValidatorResponse save3 = formTeamAddController.save("Star", "");
// then
assertTrue(save1.hasErrors());
assertTrue(save2.hasErrors());
assertTrue(save3.hasErrors());
assertEquals(TeamInputValidator.errTeamFee(), save1.getErrors().get("membershipPayment"));
assertEquals(TeamInputValidator.errTeamFee(), save2.getErrors().get("membershipPayment"));
assertEquals(TeamInputValidator.errTeamFee(), save3.getErrors().get("membershipPayment"));
}
}
持久性.xml
<persistence-unit name="entity-manager-test" transaction-type="RESOURCE_LOCAL">
<class>com.example.database.entity.Team</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS test" />
<property name="jakarta.persistence.jdbc.user" value="root" />
<property name="jakarta.persistence.jdbc.password" value="password" />
<!-- Generate the database schema -->
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<!-- Customize the schema generation behavior -->
<property name="javax.persistence.schema-generation.create-source" value="metadata"/>
<property name="javax.persistence.schema-generation.drop-source" value="metadata"/>
<property name="javax.persistence.schema-generation.scripts.action" value="none"/>
</properties>
</persistence-unit>
我认为您可以使用
@AfterEach
注释而不是 @AfterAll
来确保在每次单独测试后执行清理,因此在 H2DatabaseConfig
类中更改 @AfterEach
如下所示:
@AfterEach
public void tearDown() throws SQLException {
entityManager.clear(); //clear entities from the session
connection.close();
server.stop();
}
并编辑
persistence.xml
文件以包含带有“drop-and-create”的 javax.persistence.schema-generation.database.action
属性,以删除并重新创建每个测试的数据库架构,并在运行测试之前确保干净的状态,如下所示:
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>