如果成功登录,Spring Boot @WebMvcTest返回404

时间:2018-08-29 19:37:06

标签: java spring spring-boot testing mocking

我正在学习如何测试SpringBoot应用程序。

现在,我正在尝试通过为现有的工作项目创建测试来学​​习。

我从我的 AdminHomeController 开始,该管理员在管理员登录时管理家庭:

@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的主要部分是:

@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 与“ ADMIN”权限一起使用,则会得到404

如前所述,我的应用程序正在运行,并且只有以ADMIN身份登录时才能访问/ 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

我通过将 @ContextConfiguration(classes = MyOwnProperties.class)更改为 @Import

使它通过

所以现在我的测试如下:

@RunWith(SpringRunner.class)
@WebMvcTest(AdminHomeController.class)
@Import({SecurityConfigurationGlobal.class, MyOwnProperties.class})
public class AdminHomeControllerUnitTest { 
....... Same as before
}

我很高兴,因为考试通过了,但是有人可以向我解释原因吗?我在其他SO文章中读到,要使用以@ConfigurationProperties注释的我自己的自定义属性文件,我需要使用@ContextConfiguration注释。

1 个答案:

答案 0 :(得分:1)

我的问题的解决方案是将 @ContextConfiguration(classes = MyOwnProperties.class)替换为 @Import

因此它将变成:

@RunWith(SpringRunner.class)
@WebMvcTest(AdminHomeController.class)
@Import({SecurityConfigurationGlobal.class, MyOwnProperties.class})
public class AdminHomeControllerUnitTest { 
     ....... Same as before
}