如何在单元测试期间通过 Thymeleaf 模板的身份验证
How to pass Authentication for Thymeleasf template during unit test
我正在使用 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());
}
}
我的问题是,当我 运行 测试时,控制器上的身份验证值为空。我曾尝试添加安全上下文,但在正确设置方面遇到了问题。我该如何解决这个问题
更新:
Link 到示例存储库:https://github.com/dmbeer/thymeleaf-spring-security-test
在 Spring Boot 5.1.x 之前,您需要手动添加 Spring 安全过滤器配置:
WebTestClient webTestClient = WebTestClient
.bindToController(new ChangedPasswordController())
.webFilter(new SecurityContextServerWebExchangeWebFilter())
.apply(springSecurity())
.configureClient()
.build();
在 5.1.x 中,@WebFluxTest
会自动添加这些调用,因此您无需添加。
您可以在 the Spring Security repo 中查看示例。
所以在@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());
}
}```
我正在使用 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());
}
}
我的问题是,当我 运行 测试时,控制器上的身份验证值为空。我曾尝试添加安全上下文,但在正确设置方面遇到了问题。我该如何解决这个问题
更新: Link 到示例存储库:https://github.com/dmbeer/thymeleaf-spring-security-test
在 Spring Boot 5.1.x 之前,您需要手动添加 Spring 安全过滤器配置:
WebTestClient webTestClient = WebTestClient
.bindToController(new ChangedPasswordController())
.webFilter(new SecurityContextServerWebExchangeWebFilter())
.apply(springSecurity())
.configureClient()
.build();
在 5.1.x 中,@WebFluxTest
会自动添加这些调用,因此您无需添加。
您可以在 the Spring Security repo 中查看示例。
所以在@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());
}
}```