spring-boot - 无法在同一个 Spring Boot 集成测试中拥有 webEnvironment 和存储库访问权限
问题描述
解决方案注意事项:
@Transactional 注释和使用延迟加载存储库访问似乎是根本原因。
语境:
我正在为 SpringBoot 应用程序(v2.2.5.RELEASE)编写 Junit5 集成测试。它将使用 webEnvironment 启动 SpringBoot,调用每个 rest 端点并断言结果。
由于我们在服务层和持久层之间有一个缓存层,因此我还注入了存储库以直接检查数据库内容。
问题:
似乎我可以直接通过注入的存储库或通过最终调用同一存储库的 Web 调用访问数据库(但不确定它是否调用了相同的实例,所有 SpringBootTest 魔术都在后台进行)。
当我尝试在同一个测试用例中调用两者时,无论哪个先正确运行,第二个都失败了。
案例 A:Web 端点访问,然后是直接存储库访问
- Web 端点使用数据库,创建资源(由单独的数据库查询确认)
- 直接存储库访问没有找到任何实体,即使它清楚地在数据库中
案例 B:直接存储库访问,然后是 Web 端点访问
- 直接存储库访问创建资源(由单独的数据库查询确认)
- Web端点没有找到任何实体,即使它清楚地在数据库中
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("it")
@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
@Sql(scripts = {"classpath:schema_init.sql"})
@Transactional
public class ClientIntegrationTest {
// This is the same repository class that is at the end of the api call
@Autowired
private ClientRepository repository;
// CASE A
@Test
@DisplayName("Create a new client")
@Sql(scripts = "classpath:data_int.sql")
void createNewClientTest() {
// given
Client rawClient = new Client("testdetails");
// when
Client savedClient = Unirest
.post("myendpoint_save")
.body(rawClient)
.asObject(Client.class)
.getBody();
// then
assertThat(repository.findById(savedClient.getId()).get())
.as("The DB state is the same as the returned state")
.isEqualTo(savedClient);
}
// CASE B
@Test
@DisplayName("Get client by id")
@Sql(scripts = "classpath:data_int.sql")
void getClientByIdTest() {
// given
Client savedEntity = repository.save(new Client("testdetails"));
// when
Client retrievedClient = Unirest
.post("myendpoint_getbyid")
.queryString("clientId", savedEntity.getId())
.asObject(Client.class)
.getBody();
// then
// omitted assertions
}
}
我假设问题的根源可能与运行在单独线程中的 webEnvironment 有关,但即使这样也没有任何意义,因为数据库是这两个操作中的单一事实来源。
那么,为什么在 同一个测试用例中直接通过网络调用查看同一个数据库状态时,同一个存储库会有不同的结果呢?
解决方案
删除@Transactional
可以解决您的问题。
@Transactional
仅用于控制直接存储库访问中的事务行为。
推荐阅读
- gcloud - gcloud 构建。
没有 storage.objects.get 访问 Google Cloud Storage 对象的权限 - discord.py - 忽略命令购买中的异常
- javascript - async&await 与普通的 Promise 有何不同?
- c# - 如何使用 C# 将 Azure 文件共享中的 CSV 文件读入内存流?
- c++ - Makefile 编译问题
- javascript - 你能创建一个通用的或假的滑动动作/触摸吗?
- c - C 相邻堆栈寻址
- python - Python:在 for 循环中创建新列名
- r - 如何用大写字母模式分割文本/字符串?
- python - 无法比较类型 'ndarray(dtype=object)' 和 'Interval'