java - 如何防止测试中违反参照完整性约束?
问题描述
我使用 JUnit 5 为我的 Spring Boot 应用程序创建单元测试。
对于每个测试类,我使用 @Sql 加载上下文:
HierarchyEntityServiceTest.java
@SpringBootTest
@ActiveProfiles("test")
@Sql({
"/sql/import_hierarchy_entity_type.sql",
"/sql/import_hierarchy_entity.sql",
"/sql/import_site_department.sql"
})
@Transactional
public class HierarchyEntityServiceTest {
@Autowired
private HierarchyEntityService hierarchyEntityService;
@Test
void findAllSkillCenters() {
assertThat(hierarchyEntityService.findAllSkillCenters())
.hasSize(5);
}
@Test
void findDepartmentsBySiteAndSkillCenter() {
assertThat(hierarchyEntityService.findDepartmentsBySitesAndSkillCenter(
List.of(11L),
"DPT_SWFC1"
)).hasSize(1);
}
}
SourceDetailsRepositoryTest.java
@SpringBootTest
@ActiveProfiles("test")
@Sql({
"/sql/import_hierarchy_entity_type.sql",
"/sql/import_hierarchy_entity.sql",
"/sql/import_source_details.sql",
"/sql/import_candidate.sql"
})
@Transactional
class SourceDetailsRepositoryTest {
@Autowired
private CandidateRepository candidateRepository;
@Autowired
private SourceDetailsRepository sourceDetailsRepository;
@Test
void findAllSourceDetailsTest() {
List<SourceDetails> sourceDetails = sourceDetailsRepository.findAll();
assertEquals(10, sourceDetails.size());
assertEquals("SOURCING", sourceDetails.get(0).getType());
}
@Test
void findSourceDetailsByTypeTest() {
List<SourceDetails> sourceDetails = sourceDetailsRepository.findByType("SOURCING");
assertEquals(7, sourceDetails.size());
}
@Test
void findSourceDetailByCandidateIdTest() {
Optional<Candidate> candidate = candidateRepository.findById(1000L);
Optional<SourceDetails> sourceDetails = sourceDetailsRepository.findById(candidate.get().getSourceDetailsId());
assertEquals(6L, sourceDetails.get().getId());
}
}
如您所见,一些 SQL 脚本在多个类中被调用。
这些脚本都包含数据库中的数据:
import_hierarchy_entity.sql
INSERT INTO public.hierarchy_entity(functional_code, label, short_label, type_functional_code,
parent_entity_functional_code)
VALUES ('CC_EDGE_EMB', 'CC Edge & Embedded', 'EE', 'CC', 'DIL'),
('DPT_AD1', 'AD1', 'AD1', 'DEPT', 'CC_AUG_DATA'),
('DPT_UE2', 'UE2', 'UE2', 'DEPT', 'CC_USER_EFF'),
('DPT_UE3', 'UE3', 'UE3', 'DEPT', 'CC_USER_EFF'),
('DPT_UE4', 'UE4', 'UE4', 'DEPT', 'CC_USER_EFF'),
('DPT_UE5', 'UE5', 'UE5', 'DEPT', 'CC_USER_EFF');
import_candidate.sql
INSERT INTO public.candidate(id, first_name, last_name, sex, status, author_id, manager_id, profile_id, site_id,
authored_at, edited_at, is_deleted, arrival_on, years_of_experience, source_id,
source_details, source_details_id, dept_code, entity_code)
VALUES (1000, 'JEAN', 'Louis', 'MALE', 'PREQUALIFICATION', 'admin', 'operationnel', 1, 2, CURRENT_TIMESTAMP(),
CURRENT_TIMESTAMP(), false, CURRENT_TIMESTAMP(), 1, 1, 'Viadeo', 6, 'DPT_EE1', 'CC_EDGE_EMB');
要记住的一件事是,有些表有一个功能代码,它是一个字符串,作为主键。
这是用于我的测试的 Spring Boot 配置文件的配置:
应用程序.yml
spring:
profiles: test
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
username: sa
password:
data:
classpath: import.sql
jpa:
database-platform: org.hibernate.dialect.H2Dialect
generate-ddl: true
hibernate:
default_schema: public
ddl-auto: create
show-sql: true
flyway:
enabled: false
当我单独运行测试时,它工作正常。但是,当我运行命令时mvn test
,我会遇到相同类型的失败:
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException:
Intégrité référentielle violation de contrainte: "FK87J5L5FKHUUWS58S4QUJU65O6: PUBLIC.CANDIDATE FOREIGN KEY(AUTHOR_ID) REFERENCES PUBLIC.MYREC_USER(ID) ('admin')"
Referential integrity constraint violation: "FK87J5L5FKHUUWS58S4QUJU65O6: PUBLIC.CANDIDATE FOREIGN KEY(AUTHOR_ID) REFERENCES PUBLIC.MYREC_USER(ID) ('admin')"; SQL statement:
INSERT INTO public.candidate(id, first_name, last_name, sex, status, author_id, manager_id, profile_id, site_id, authored_at, edited_at, is_deleted, arrival_on, years_of_experience, source_id, source_details, source_details_id, dept_code, entity_code) VALUES (1000, 'JEAN', 'Louis', 'MALE', 'PREQUALIFICATION', 'admin', 'operationnel', 1, 2, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP(), false, CURRENT_TIMESTAMP(), 1, 1, 'Viadeo', 6, 'DPT_EE1', 'CC_EDGE_EMB') [23506-200]
[ERROR] findAllSourceDetailsTest Time elapsed: 0.09 s <<< ERROR!
当一个类尝试加载 SQL 脚本时,数据库似乎不干净。此外,文件import.sql似乎与此无关,因为它不加载相同的数据,并且当我删除它时问题仍然存在。
在每个测试类调用之前不应该清理上下文吗?
是否可以对多个测试类继续使用相同的脚本并避免这种情况?
解决方案
您可以使用以下内容来注释您的测试类,而不是 @Sql 注释。您可以为各自的测试类提供适当的 sql 脚本列表。
@SqlGroup({@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:schema.sql", "import_hierarchy_entity_type.sql", "import_hierarchy_entity.sql", "import_source_details.sql", "import_candidate.sql"})})
我添加了 schema.sql 作为示例,以防您想在每次测试后删除并重新创建架构。代码要做的是在每个测试方法之前执行脚本。
注意:您还可以将 @Transactional 替换为 @DataJpaTest 以获得更多 JPA 支持。
推荐阅读
- javascript - 基于特定对象之间的对象 ID 序列的数组连接
- python-multiprocessing - 如何使用带有 .apply 功能的 multiprocess.Pool?
- c++ - C++:简化#define
- python - 下载特定区域的 CMIP6 数据
- php - 在外部域上通过 IIS 运行 PHP
- sql - 多个选择语句不起作用但单独会(循环和大小写)
- javascript - InertiaJS 在验证错误后保留表单数据
- javascript - paytm_allinone_react-native 支付在生产模式下失败
- mysql - GROUP BY 并选择具有两列条件的最大 ID
- javascript - Javascript:替换多行字符串中第 n 次出现的子字符串