gpt4 book ai didi

spring - spring boot 测试中的事务未回滚

转载 作者:行者123 更新时间:2023-11-29 11:24:05 25 4
gpt4 key购买 nike

我的 UserController 有一个集成测试类.下面这个类的内容是:

// imports...

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
@Transactional
@Rollback
public class UserControllerTests {

private static final String ENDPOINT = "/v1/users";

@Autowired
private TestRestTemplate restTemplate;

@Autowired
private ApplicationProperties applicationProperties;

@Test
public void test_user_create() {
String token = login("test", "test");
HttpEntity<UserRequest> request = createRequest(token, "admin", "admin");
ResponseEntity<User> response = restTemplate.exchange(ENDPOINT, HttpMethod.POST, request, User.class);

assertEquals(HttpStatus.CREATED, response.getStatusCode());
}

private HttpEntity createRequest(String token) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.set("Authorization", String.format("Bearer %s", token));
return new HttpEntity(headers);
}

private HttpEntity<UserRequest> createRequest(String token, String username, String password) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.set("Authorization", String.format("Bearer %s", token));
return new HttpEntity<>(new UserRequest(username, password), headers);
}

private String login(String username, String password) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.set("Authorization", String.format("Basic %s", Base64.getEncoder().encodeToString(String.format("%s:%s", applicationProperties.getAuth().getClientId(), applicationProperties.getAuth().getClientSecret()).getBytes())));
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "password");
body.add("username", username);
body.add("password", password);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
ResponseEntity<OAuth2AccessToken> response = restTemplate.exchange("/oauth/token", HttpMethod.POST, request, OAuth2AccessToken.class);
return response.getBody().getValue();
}
}

当我执行这个测试类两次时,第二次失败了,因为数据库中已经有一个用户名为admin 的用户。 (唯一约束)。

我正在针对 postgres 进行测试与我的生产环境中的数据库相同。该应用程序正在使用 Spring 的 jdbcTemplate用于数据库操作。

我的日志记录产生了以下日志:

2017-10-13 14:11:31.407  INFO [iam-service,,,] 63566 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context 
...
2017-10-13 14:11:32.050 INFO [iam-service,,,] 63566 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test context

我的申请流程是<request> --> <controller> --> <service with jdbcTemplate>服务用 @Transactional 注释.

我真的被这个困住了。

找到的一个解决方案对我不起作用,它正在创建一个 PlatformTransactionManager用于测试配置的 bean:

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}

最佳答案

据官方Spring Boot documentation当您直接从“web 层”应用它时,不支持数据库事务回滚:

If your test is @Transactional, it will rollback the transaction at the end of each test method by default. However, as using this arrangement with either RANDOM_PORT or DEFINED_PORT implicitly provides a real servlet environment, HTTP client and server will run in separate threads, thus separate transactions. Any transaction initiated on the server won’t rollback in this case.

我建议您考虑以下选项:

  • web controller 使用单独的测试层和database单元测试情况下的层

  • 在执行集成测试时,在执行测试方法之前创建/恢复表并删除/清除它们。当 Db 架构很大时,这种方法可能会产生很大的开销,但您可以根据需要有选择地清除/恢复数据。

关于spring - spring boot 测试中的事务未回滚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46729849/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com