简体   繁体   English

使用 SpringSecurity 和 Mock 进行 Spring Boot 单元测试

[英]Spring Boot unit test with SpringSecurity and Mock

Currently I have several unit tests that's working correctly.目前我有几个单元测试可以正常工作。 In my unit test, on init, I have included the following code:在我的单元测试中,在 init 中,我包含了以下代码:

@Mock
private UsersServices usersServices;

@InjectMocks
private UsersController usersControllers;

@Before
public void init() {
  this.mvc = MockMvcBuilders.standaloneSetup(usuariosController)
                            .addFilter(springSecurityFilterChain)
                            .setControllerAdvice(new UsuariosControllerAdvice(logService)).build();
}

this worked great, but some authorizations annotations, like @PreAuthorize are ignored.这很好用,但忽略了一些授权注释,例如@PreAuthorize (In my WebSecurityConfig, I already added the @EnableGlobalMethodSecurity(prePostEnabled = true) annotation. (在我的 WebSecurityConfig 中,我已经添加了@EnableGlobalMethodSecurity(prePostEnabled = true)注释。

So, after some time, I found the following code:所以,过了一段时间,我找到了以下代码:

@Mock
private UsersServices usersServices;

@InjectMocks
private UsersController usersControllers;

@Autowired
private WebApplicationContext wac;

@Before
public void init() {
  this.mvc = MockMvcBuilders
      .webAppContextSetup(wac)
      .addFilter(springSecurityFilterChain)
      apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain))
      .build();
}

and now, the authorization annotations ( @PreAuthorize ) works, but the UsersServices mock don't.现在,授权注释( @PreAuthorize )有效,但UsersServices模拟无效。 When I call my controller method on unit tests, the real UserServices was called, not the mock.当我在单元测试中调用我的控制器方法时,调用的是真正的UserServices ,而不是模拟。

Here is a unit test that mock a UserServices :这是一个模拟UserServices的单元测试:

when(usersServices.getUserAvatar(anyString())).thenReturn(
    CompletableFuture.completedFuture(Optional.empty()));

MvcResult result = mvc.perform(
    get("/api/users/avatar/{login:.+}", "mock.user")
        .header("Authorization", testHelpers.buildJwtToken("USER")))
        .andReturn();

    mvc.perform(asyncDispatch(result))
       .andExpect(status().isNotFound());

without the standaloneSetup , the real userServices.getUserAvatar is called.没有standaloneSetup ,真正的userServices.getUserAvatar被调用。

This happens because your WebApplicationContext is not aware of your UsersController with mocked UsersServices .发生这种情况是因为您的WebApplicationContext不知道您的UsersControllerUsersServices To fix this you have two options:要解决此问题,您有两个选择:

The first option is to use第一个选项是使用

@MockBean
private UsersServices usersServices;

instead of:代替:

@Mock
private UsersServices usersServices;

This will add mocked bean into application context so that the Spring is aware of it and, thus, will use it instead of a real one.这会将模拟 bean 添加到应用程序上下文中,以便 Spring 知道它,因此将使用它而不是真正的 bean。

The second option is to set your controller directly inside WebApplicationContext manually.第二个选项是直接在WebApplicationContext手动设置控制器。 This option should not be "tried at home", but can be a workaround for cases when you do not have @MockedBean because of the old spring version:此选项不应“在家尝试”,但可以作为由于旧的 spring 版本而没有@MockedBean情况的解决方法:

AutowireCapableBeanFactory factory = wac.getAutowireCapableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
registry.removeBeanDefinition(beanId);

//create newBeanObj through GenericBeanDefinition

registry.registerBeanDefinition(beanId, newBeanObj);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM