无法在同一个 Spring 引导集成测试中访问 webEnvironment 和存储库
Unable to have webEnvironment and repository access in the same Spring Boot Integration Test
解法注意事项:
@Transactional 注释和使用延迟加载存储库访问似乎是根本原因。
上下文:
我正在为 SpringBoot 应用程序 (v2.2.5.RELEASE) 编写 Junit5 集成测试。它将使用 webEnvironment 启动 SpringBoot,调用每个 rest 端点并断言结果。
由于我们在服务层和持久层之间有一个缓存层,因此我还注入了存储库以直接检查数据库内容。
问题:
我似乎可以直接通过注入的存储库或通过最终 调用相同存储库 的网络调用访问数据库(但不确定它是否调用相同的实例,所有 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
仅用于控制直接存储库访问中的事务行为。
解法注意事项:
@Transactional 注释和使用延迟加载存储库访问似乎是根本原因。
上下文:
我正在为 SpringBoot 应用程序 (v2.2.5.RELEASE) 编写 Junit5 集成测试。它将使用 webEnvironment 启动 SpringBoot,调用每个 rest 端点并断言结果。
由于我们在服务层和持久层之间有一个缓存层,因此我还注入了存储库以直接检查数据库内容。
问题:
我似乎可以直接通过注入的存储库或通过最终 调用相同存储库 的网络调用访问数据库(但不确定它是否调用相同的实例,所有 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
仅用于控制直接存储库访问中的事务行为。