Java 如果登录成功,Spring Boot@WebMvcTest将返回404
我正在学习如何测试我的SpringBoot应用程序 现在我正试图通过为现有的工作项目创建测试来学习 我从管理员登录时管理主页的AdminHomeController开始:Java 如果登录成功,Spring Boot@WebMvcTest将返回404,java,spring,spring-boot,testing,mocking,Java,Spring,Spring Boot,Testing,Mocking,我正在学习如何测试我的SpringBoot应用程序 现在我正试图通过为现有的工作项目创建测试来学习 我从管理员登录时管理主页的AdminHomeController开始: @Controller @RequestMapping("/admin/home") public class AdminHomeController { private UsuarioService usuarioService; @Autowired public AdminHomeController(Usuario
@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"));
}
}
我认为我的证券配置的相关部分是:
@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的静态最终定义
由于缺乏经验,我不能理解的是我的测试结果
如果我删除@WithMockUser,我会得到预期的401
如果我将@WithMockUser与ADMIN以外的任何其他权限一起使用,我会得到一个403,这也是预期的响应
最后,如果我使用具有管理权限的@WithMockUser,那么我会得到一个404
如上所述,我的应用程序正在运行,只有以管理员身份登录,我才能访问/admin/home
使现代化
运行另一个类似的测试可以很好地工作,但是这个测试需要加载完整的SpringBoot应用程序。我认为这将是一个集成测试,我只想单独测试控制器。仅使用@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的@ContextConfigurationclasses=MyOwnProperties.class使其通过
现在我的测试看起来像:
@RunWith(SpringRunner.class)
@WebMvcTest(AdminHomeController.class)
@Import({SecurityConfigurationGlobal.class, MyOwnProperties.class})
public class AdminHomeControllerUnitTest {
....... Same as before
}
我很高兴,因为考试通过了,但是有人能告诉我为什么吗?我在另一篇文章中读到,要使用带有@ConfigurationProperties注释的自定义属性文件,我需要使用@ContextConfiguration注释。我的问题的解决方案是将@ContextConfigurationclasses=MyOwnProperties.class替换为@Import 因此,它将成为:
@RunWith(SpringRunner.class)
@WebMvcTest(AdminHomeController.class)
@Import({SecurityConfigurationGlobal.class, MyOwnProperties.class})
public class AdminHomeControllerUnitTest {
....... Same as before
}
更新SpringBoot 2.x
我现在已经将我的代码库迁移到SpringBoot2.4.1,这个测试再次失败。经过反复试验,现在需要将@Import替换为@ContextConfiguration。我的问题的解决方案是将@ContextConfigurationclasses=MyOwnProperties.class替换为@Import 因此,它将成为:
@RunWith(SpringRunner.class)
@WebMvcTest(AdminHomeController.class)
@Import({SecurityConfigurationGlobal.class, MyOwnProperties.class})
public class AdminHomeControllerUnitTest {
....... Same as before
}
更新SpringBoot 2.x
我现在已经将我的代码库迁移到SpringBoot2.4.1,这个测试再次失败。经过反复试验,现在需要将@Import替换为@ContextConfiguration。你救了我一天:我也遇到了同样的问题。你发现需要这个的原因了吗?我很高兴这有帮助。但我还是不知道为什么会这样。任何意见都将受到赞赏@Andreaolci现在来看,对于SpringBoot2,正确的注释是@ContextConfiguration。这更有意义,也许这是以前的Spring Boot版本中的一个bug,这就是为什么我们无法找到需要它的原因。你救了我一天:我也有同样的问题。你发现需要这个的原因了吗?我很高兴这有帮助。但我还是不知道为什么会这样。任何意见都将受到赞赏@Andreaolci现在来看,对于SpringBoot2,正确的注释是@ContextConfiguration。这更有意义,也许这是以前Spring Boot版本中的一个bug,这就是为什么我们无法找到需要它的原因