【问题标题】:Mock WebSecurity dependencies when testing controllers in Spring在 Spring 中测试控制器时模拟 WebSecurity 依赖项
【发布时间】:2019-07-30 12:21:49
【问题描述】:

为了对我的控制器进行快速测试,我想使用@WebMvcTest。我为控制器编写了服务器端单元测试。这些基本上是涉及切片 Spring 应用程序上下文的简单单元测试:

@WebMvcTest(DemoController.class)
class DemoControllerTests {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithAnonymousUser
    void shouldNotHaveAccessWhenAnonymous() throws Exception {
        this.mockMvc.perform(get("/"))
                .andExpect(status().isUnauthorized());
    }

    @Test
    @WithMockUser(username = "pascal", roles = "USER")
    void shouldHaveAccessWithUserRole() throws Exception {
        this.mockMvc.perform(get("/hello"))
                .andExpect(status().isOk())
                .andExpect(content().string("Hello"));
    }
}

控制器如下所示:

@RestController
class DemoController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello";
    }

    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/admin")
    public String admin() {
        return "Admin";
    }

}

但是一旦开始在我的WebSecurityConfig 中涉及更多依赖项,例如MyUserDetailsService(它本身依赖于UserObjectRepository),问题就会开始出现。

@Autowired
public WebSecurityConfig(final MyUserDetailsService myUserDetailsService) {
    this.myUserDetailsService = myUserDetailsService;
}

当我运行测试时,Spring 无法加载 ApplicationContext (NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.MyUserDetailsService' available)。

当我查看@WebMvcTest 的文档时,这确实是有道理的。它说组件、服务和存储库不会自动配置。但在最后一节中,它说 Spring Security 将在使用此注释时自动配置。可使用@AutoConfigureMockMvc 进行其他配置。

从我的角度来看,没有什么特别的事情要做,即使我想在@AutoConfigureMockMvc 中设置secure 配置,它在默认情况下已启用并已弃用。他们提到 secure 属性自 2.1.0 起已弃用,以支持 Spring Security 的测试支持。但我找不到有关此主题的专用 Spring Security 测试支持的更多详细信息(我已经在我的测试中使用 @WithMockUser 等)

 * <p>
 * Using this annotation will disable full auto-configuration and instead apply only
 * configuration relevant to MVC tests (i.e. {@code @Controller},
 * {@code @ControllerAdvice}, {@code @JsonComponent},
 * {@code Converter}/{@code GenericConverter}, {@code Filter}, {@code WebMvcConfigurer}
 * and {@code HandlerMethodArgumentResolver} beans but not {@code @Component},
 * {@code @Service} or {@code @Repository} beans).
 * <p>
 * By default, tests annotated with {@code @WebMvcTest} will also auto-configure Spring
 * Security and {@link MockMvc} (include support for HtmlUnit WebClient and Selenium
 * WebDriver). For more fine-grained control of MockMVC the
 * {@link AutoConfigureMockMvc @AutoConfigureMockMvc} annotation can be used.
 * <p>

测试总体上都很好。他们测试控制器方法及其方法安全配置。当我添加更多依赖项和单独的类时,问题才开始出现,然后我尝试将它们注入我的WebSecurityConfig

如何模拟这些依赖项,以便我的控制器测试使用切片上下文,而不是使用 @SpringBootTest 启动整个应用程序上下文?

【问题讨论】:

  • 你能添加你的控制器代码吗?无论如何,您可以使用 @MockBean 注释来模拟这些依赖项:docs.spring.io/spring-boot/docs/current/api/org/springframework/…
  • 是的,我可以用@MockBean 模拟控制器的依赖关系,但这里不是这样。我的 WebSecurityConfig 中有依赖项,而不是控制器中。
  • 作为我提到的文档,@MockBean 在 spring 上下文中模拟 bean,而不是控制器。
  • 你在用@RunWith(SpringRunner.class)运行你的测试
  • 是的,@MockBean 可以做到这一点,但这意味着我必须在使用 Security 的每个测试中模拟来自 WebSecurityConfig 的依赖项。这意味着整个应用程序中的每个控制器。这对我来说没有意义。

标签: spring-mvc testing spring-security


【解决方案1】:

因此安全配置显然已加载,否则您不必费心@WithMockUser 等。然后您可以使用 Spring 的 @MockBean 注释来模拟 WebSecurityConfig 中的依赖项。

https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/MockBean.html

可用于向 Spring 添加模拟的注解 应用上下文

为避免测试类中的重复,您可以创建一个抽象的基础测试类,您的控制器测试将对其进行扩展:

public abstract class BaseControllerTest{

   @MockBean
   private UserDetailsService userDetailsService;
}

对于这种情况应该就是这样。对于您需要控制其行为的任何模拟 bean,您可以使用标准的 Mockito 功能。

【讨论】:

    猜你喜欢
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-05
    • 1970-01-01
    • 2021-12-03
    • 2023-03-13
    • 1970-01-01
    相关资源
    最近更新 更多