目前我有几个正常工作的单元测试。在我的单元测试中,在 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();
}
这很好用,但一些授权注释(如@PreAuthorize
)被忽略了。(在我的网络安全配置中,我已经添加了@EnableGlobalMethodSecurity(prePostEnabled = true)
注释。
所以,过了一段时间,我找到了以下代码:
@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();
}
现在,授权注释(@PreAuthorize
)有效,但UsersServices
模拟不起作用。当我在单元测试中调用控制器方法时,调用的是真正的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());
没有standaloneSetup
,就叫真正的userServices.getUserAvatar
。
发生这种情况是因为您的WebApplicationContext
不知道您的UsersController
与模拟UsersServices
。要解决此问题,您有两种选择:
第一种选择是使用
@MockBean
private UsersServices usersServices;
而不是:
@Mock
private UsersServices usersServices;
这会将模拟的 bean 添加到应用程序上下文中,以便 Spring 知道它,因此会使用它而不是真实的 bean。
第二种选择是手动直接在WebApplicationContext
内设置控制器。此选项不应"在家尝试",但对于由于旧的 spring 版本而没有@MockedBean
的情况,可以作为一种解决方法:
AutowireCapableBeanFactory factory = wac.getAutowireCapableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
registry.removeBeanDefinition(beanId);
//create newBeanObj through GenericBeanDefinition
registry.registerBeanDefinition(beanId, newBeanObj);