首页 > 解决方案 > 无法在同一个 Spring Boot 集成测试中拥有 webEnvironment 和存储库访问权限

问题描述

解决方案注意事项:

@Transactional 注释和使用延迟加载存储库访问似乎是根本原因。

语境:

我正在为 SpringBoot 应用程序(v2.2.5.RELEASE)编写 Junit5 集成测试。它将使用 webEnvironment 启动 SpringBoot,调用每个 rest 端点并断言结果。

由于我们在服务层和持久层之间有一个缓存层,因此我还注入了存储库以直接检查数据库内容。

问题:

似乎我可以直接通过注入的存储库或通过最终调用同一存储库的 Web 调用访问数据库(但不确定它是否调用了相同的实例,所有 SpringBootTest 魔术都在后台进行)。

当我尝试在同一个测试用例中调用两者时,无论哪个先正确运行,第二个都失败了。

案例 A:Web 端点访问,然后是直接存储库访问

案例 B:直接存储库访问,然后是 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 有关,但即使这样也没有任何意义,因为数据库是这两个操作中的单一事实来源。

那么,为什么在 同一个测试用例中直接通过网络调用查看同一个数据库状态时,同一个存储库会有不同的结果呢?

标签: spring-bootspring-data-jpaintegration-testingjunit5spring-test

解决方案


删除@Transactional可以解决您的问题。

@Transactional仅用于控制直接存储库访问中的事务行为。


推荐阅读