spring-boot - 如何在单元测试期间通过 Thymeleasf 模板的身份验证
问题描述
我正在使用 Spring Boot 2.0.8.RELEASE。我有一个控制器,它具有以下方法构造
@PostMapping(value = "/profile/change-password", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public Mono<String> changePasswordSubmit(Authentication authentication, @RequestBody MultiValueMap<String, String> formData) {
我的单元测试看起来像:
@RunWith(SpringRunner.class)
@WebFluxTest(controllers = ChangePasswordController.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Import({ThymeleafAutoConfiguration.class, SpringSecurityContextUtils.class})
@WithMockUser(username = "test", password = "password")
public class ChangePasswordControllerTest {
@Autowired
WebTestClient webTestClient;
@MockBean
SpringUserDetailsRepository userDetailsRepository;
@Autowired
ChangePasswordController controller;
@MockBean
Authentication authentication;
@Test
public void addNewEntrySubmit() {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.put("password1", Collections.singletonList("password"));
formData.put("password2", Collections.singletonList("password"));
webTestClient.post().uri("/profile/change-password").contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData(formData)).exchange().expectStatus().isSeeOther().expectHeader().valueEquals(HttpHeaders.LOCATION, "/page/1");
// verify(userDetailsRepository).updatePassword(captor.capture(), captor.capture());
doNothing().when(userDetailsRepository).updatePassword(any(), any());
}
}
我的问题是,当我运行测试时,控制器上的 Authentication 值为 null。我已尝试添加安全上下文,但在正确设置时遇到了问题。我该如何解决
更新:链接到示例存储库:https ://github.com/dmbeer/thymeleaf-spring-security-test
解决方案
因此,在@jzheaux 和相关文档的帮助下,以及 webflux 指南https://docs.spring.io/spring-security/site/docs/5.0.11.RELEASE/reference/html/test-webflux.html
我的单元测试如下所示:
@RunWith(SpringRunner.class)
@Import({ThymeleafAutoConfiguration.class})
@WebFluxTest(controllers = ChangePasswordController.class)
@WithMockUser(username = "test", authorities = {"ROLE_ADMIN"})
@ContextConfiguration
public class ChangePasswordControllerTest {
@Autowired
ApplicationContext context;
private WebTestClient webTestClient;
@MockBean
SpringUserDetailsRepository userDetailsRepository;
@Captor
private ArgumentCaptor<String> captor;
@Before
public void setUp() throws Exception {
webTestClient = WebTestClient.bindToApplicationContext(context)
.webFilter(new SecurityContextServerWebExchangeWebFilter())
.apply(springSecurity())
.configureClient()
.build();
}
@Test
public void getChangePasswordPageTest() {
EntityExchangeResult<String> result = webTestClient
.mutateWith(csrf())
.get().uri("/profile/change-password")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).returnResult();
assertThat(result.getResponseBody(), stringContainsInOrder(Arrays.asList("<title>Change Password</title>",
"<input type=\"password\" class=\"form-control\" id=\"password1\" name=\"password1\">")));
}
@Test
public void addNewEntrySubmit() {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.put("password1", Collections.singletonList("password"));
formData.put("password2", Collections.singletonList("password"));
given(userDetailsRepository.updatePassword(any(), any())).willReturn(Mono.empty());
webTestClient.mutateWith(csrf()).post().uri("/profile/change-password").contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData(formData)).exchange().expectStatus().isSeeOther().expectHeader().valueEquals(HttpHeaders.LOCATION, "/page/1");
verify(userDetailsRepository).updatePassword(captor.capture(), captor.capture());
// doNothing().when(userDetailsRepository).updatePassword(any(), any());
}
}```
推荐阅读
- http - 当 OPTIONS 方法不可缓存时,为什么要在 Access-Control-Request-Method、ACRH 和 origin 上添加 Vary?
- javascript - 文档不鼓励使用 Vue 更改数据的方法 - 但为什么呢?
- algorithm - 具有调度约束和优化的黑客松团队分配
- c++ - 使用迭代器的 C++ 合并排序
- c++ - 传递 char 值数组时 const char* 如何工作?
- kotlin - 依赖于 CoreLocation 的 Kotlin Native cinterop 框架
- r - 将R多个循环的输出存储到列表中
- javascript - React Router 将数据从一个组件传递到另一个组件
- javascript - 我如何从猫鼬模型中的另一个模型访问字段
- python - Safari WebDriver:如何单击以启用地理位置