如果登录成功,Spring Boot @WebMvcTest 返回 404 [英] Spring Boot @WebMvcTest returns 404 if success login
问题描述
我正在学习如何测试我的 SpringBoot 应用程序.
I'm learning how to Test my SpringBoot Apps.
现在我正在尝试通过为现有工作项目创建测试来学习.
Right now I'm trying to learn by creating test for an existing working project.
我从我的 AdminHomeController 开始,它在管理员登录时管理主页:
I started with my AdminHomeController that manages the Home when admins login:
@Controller
@RequestMapping("/admin/home")
public class AdminHomeController {
private UsuarioService usuarioService;
@Autowired
public AdminHomeController(UsuarioService usuarioService) {
this.usuarioService = usuarioService;
}
@RequestMapping(value={"", "/"}, method = RequestMethod.GET)
public ModelAndView admin_home(){
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Usuario loggedUser = usuarioService.findUsuarioByUsername(auth.getName());
modelAndView.addObject("userFullName", loggedUser.getNombre() + " " + loggedUser.getApellido());
modelAndView.addObject("userGravatar", Utils.getGravatarImageLink(loggedUser.getEmail()));
modelAndView.addObject("totalUsuarios", usuarioService.getUsuariosCount());
modelAndView.setViewName("admin/home");
return modelAndView;
}
}
这是我的测试:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = MyOwnProperties.class)
@WebMvcTest(AdminHomeController.class)
@Import(SecurityConfigurationGlobal.class)
public class AdminHomeControllerUnitTest {
@Autowired
private MockMvc mockMvc;
@MockBean
UsuarioService usuarioService;
@Autowired
MyOwnProperties myOwnProperties;
@MockBean
FacebookProfileService facebookProfileService;
@MockBean
MobileDeviceService mobileDeviceService;
@MockBean
PasswordEncoder passwordEncoder;
@MockBean
CustomAuthenticationProvider customAuthenticationProvider;
@Test
@WithMockUser(username = "user1", password = "pwd", authorities = "ADMIN")
public void shouldAllowAdminAccess() throws Exception{
when(usuarioService.findUsuarioByUsername("user1")).thenReturn(new Usuario());
mockMvc.perform(get("/admin/home"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("admin/home"));
}
}
而且我认为我的 SecurityConfig 的相关部分是:
And I think that the relevan part of my SecurityConfig would be:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/", "/login", "/error/**", "/home").permitAll()
.antMatchers(
myOwnProperties.getSecurity().getJwtLoginURL(),
myOwnProperties.getSecurity().getFacebookLoginURL()).permitAll()
.antMatchers("/registration", "/registrationConfirm/**").permitAll()
.antMatchers("/resetPass", "/resetPassConfirm/**", "/updatePass").permitAll()
.antMatchers("/admin/**").hasAuthority(AUTHORITY_ADMIN)
.antMatchers("/user/**").hasAuthority(AUTHORITY_USER)
.anyRequest().authenticated()
.and()
.csrf().disable()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.successHandler(new CustomUrlAuthenticationSuccessHandler())
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.exceptionHandling().accessDeniedPage("/403");
}
AUTHORITY_ADMIN 是ADMIN"的静态最终定义.
And AUTHORITY_ADMIN is a static final definition of "ADMIN".
由于缺乏经验,我无法理解的是我的测试结果.
What I can not understand due to my lack of experience are my test results.
- 如果我删除 @WithMockUser,我会按预期得到 401
- 如果我将 @WithMockUser 与ADMIN"以外的任何其他权限一起使用,我会收到 403,这也是预期的响应
- 最后,如果我使用具有管理员"权限的 @WithMockUser 那么我会得到 404
- If I remove the @WithMockUser I get a 401 as expected
- If I use the @WithMockUser with ANY other authority than "ADMIN" I get a 403 that would also be the expected response
- And finally if I use the @WithMockUser with "ADMIN" authority then I get a 404
如前所述,我的应用正在运行,如果以管理员身份登录,我只能访问/admin/home.
As said, my app is working and I can only access /admin/home if logged in as ADMIN.
运行另一个类似的测试工作正常,但这个需要加载完整的 SpringBoot 应用程序.我认为这将是一个集成测试,我只想单独"测试控制器.只有一个切片使用@WebMvcTest
Running this other similiar test works fine, but this one requieres the FULL SpringBoot app to load. I think it would be an integration test and I only want to test the controller "alone". Only a slice using @WebMvcTest
@SpringBootTest
@AutoConfigureMockMvc
public class AdminHomeControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UsuarioService usuarioService;
@Test
@WithMockUser(username = "user1", password = "pwd", authorities = "ADMIN")
public void shouldAllowAdminAccess() throws Exception{
when(usuarioService.findUsuarioByUsername(anyString())).thenReturn(new Usuario());
mockMvc.perform(get("/admin/home"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("admin/home"));
}
}
更新 2
我通过为 @Import
所以现在我的测试看起来像:
So now my test looks like:
@RunWith(SpringRunner.class)
@WebMvcTest(AdminHomeController.class)
@Import({SecurityConfigurationGlobal.class, MyOwnProperties.class})
public class AdminHomeControllerUnitTest {
....... Same as before
}
我很高兴,因为测试通过了,但有人能解释一下为什么吗?我在其他 SO 帖子中阅读,要使用我自己的带有 @ConfigurationProperties 注释的自定义属性文件,我需要使用 @ContextConfiguration 注释.
I'm happy because the test pass but can someone explain me why? I was reading in other SO post that to use my own custom properties files annotated with @ConfigurationProperties I need to use @ContextConfiguration annotation.
推荐答案
我的问题的解决方案是将 @ContextConfiguration(classes = MyOwnProperties.class) 替换为 @Import强>
The solution to my problem was to replace @ContextConfiguration(classes = MyOwnProperties.class) for a @Import
所以它会变成:
@RunWith(SpringRunner.class)
@WebMvcTest(AdminHomeController.class)
@Import({SecurityConfigurationGlobal.class, MyOwnProperties.class})
public class AdminHomeControllerUnitTest {
....... Same as before
}
更新 SpringBoot 2.x
我现在已将我的代码库迁移到 Spring Boot 2.4.1
并且此测试再次开始失败.经过反复试验,现在需要将 @Import 替换为 @ContextConfiguration.
UPDATE SpringBoot 2.x
I've now migrated my code base to Spring Boot 2.4.1
and this test start failing again. After trial and error, now the @Import need to be replaced with @ContextConfiguration.
这篇关于如果登录成功,Spring Boot @WebMvcTest 返回 404的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!