在Spring Boot 1.4中使用@WebMvcTest配置MockMvc进行MVC测试

17

我有一些可以用新的Spring Boot 1.4 @WebMvcTest以不同方式设置MockMVc的工作代码。我理解standaloneSetup方法的使用。我想知道的是通过WebApplicationContext设置MockMvc和通过自动装配MockMvc之间的区别。

代码片段1:通过WebApplicationContext设置MockMvc

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = ProductController.class)
public class ProductControllerTest {

private MockMvc mockMvc;

@Autowired
private WebApplicationContext webApplicationContext;

@MockBean
private ProductService productServiceMock;

@Before
public void setUp() {
     mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

@Test
public void testShowProduct() throws Exception {      

    Product product1 = new Product();
    /*Code to initialize product1*/

    when(productServiceMock.getProductById(1)).thenReturn(product1);

    MvcResult result = mockMvc.perform(get("/product/{id}/", 1))
            .andExpect(status().isOk())
            /*Other expectations*/
            .andReturn();
  }
}
根据WebMvcTest API文档,@WebMvcTest注释的测试默认情况下也会自动配置Spring Security和MockMvc。因此,在这里我希望看到401未经授权的状态代码,但是测试通过了200状态代码。
接下来,我尝试自动装配MockMvc,但是除非我添加@AutoConfigureMockMvc(secure = false)或更新@WebMvcTest注释以禁用安全性,否则测试将失败且返回401未授权状态代码。
@WebMvcTest(controllers = IndexController.class, secure = false)


以下是仅在显式禁用安全性后才能通过的代码。

代码片段2:通过自动连接的MockMvc

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = ProductController.class)
@AutoConfigureMockMvc(secure=false)
public class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@MockBean
private ProductService productServiceMock;

@Test
public void testShowProduct() throws Exception {      

    Product product1 = new Product();
    /*Code to initialize product1*/

    when(productServiceMock.getProductById(1)).thenReturn(product1);

    MvcResult result = mockMvc.perform(get("/product/{id}/", 1))
            .andExpect(status().isOk())
            /*Other expectations*/
            .andReturn();
  }
}

所以我的问题是:

  1. 为什么代码段1没有报告401未经授权状态码错误,而自动装配MockMvc却报告了。同时重申官方文档中的内容:默认情况下,使用@WebMvcTest注释的测试还将自动配置Spring Security和MockMvc。 但是,在这种情况下,似乎@WebMvcTest与自动配置Spring Security无关(因为代码段1通过而无任何401错误)。最后,这归结于我如何设置MockMvc。我这里正确吗?

  2. 两种方法之间的差异/目标是什么?

  3. 如何通过@AutoConfigureMockMvc(secure=false)禁用安全性,与通过@WebMvcTest(controllers=IndexController.class, secure=false)有何区别?哪种方法更可取或何时(或何处)使用它们?

4个回答

10

我也遇到了类似的问题。 @WebMvcTest会自动配置基本身份验证的Spring Security,但我有一个WebSecurityConfig类,该类扩展了WebSecurityConfigurerAdapter。在这个类中,我禁用了基本认证并配置了令牌基础安全性。这意味着WebSecurityConfig类未被用于配置Spring Security。

为解决此问题,我将@ContextConfiguration添加到我的单元测试类中,并添加了WebSecurityConfig类的依赖模拟对象。

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = CategoryRestService.class)
@ContextConfiguration(classes = {MjApplication.class, WebSecurityConfig.class})
public class CategoryRestServiceTest {
    
    @MockBean
    private CategoryRepository repository;
    
    @MockBean
    CurrentUserDetailsService currentUserDetailsService;
    
    @MockBean
    TokenAuthProvider tokenAuthProvider;
    
    @Autowired
    MockMvc mockMvc;
    
    private MediaType contentType = new    MediaType(MediaType.APPLICATION_JSON.getType(),
            MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
    
    
    @Test
    public void getCategories() throws Exception {
        Category category1 = new Category();
        category1.setName("Test Category 1");
        category1.setId(1L);
        Category category2 = new Category();
        category2.setName("Test Category 2");
        category2.setId(2L);
        List<Category> categoryList = new ArrayList<Category>();
        categoryList.add(category1);
        categoryList.add(category2);
        given(this.repository.findAll())
        .willReturn(categoryList);
        mockMvc.perform(get("/public/rest/category"))
        .andExpect(status().isOk())
        .andExpect(content().contentType(contentType))
        .andExpect(jsonPath("$[0].id", is(1)))
        .andExpect(jsonPath("$[0].name", is("Test Category 1")))
        .andExpect(jsonPath("$[1].id", is(2)))
        .andExpect(jsonPath("$[1].name", is("Test Category 2")));
    }

}

6
根据Github上的这个问题

https://github.com/spring-projects/spring-boot/issues/5476

@WebMvcTest默认情况下会自动配置基本身份验证,当spring-security-test在类路径中时

回答您的问题:

  1. 在代码片段1中,您没有将MockMvc注入到测试类中,您应该在设置方法的构建器中添加.apply(springSecurity()),这样Spring将使用基本配置(如果您有自定义安全配置,则不使用自定义安全配置)
  2. 两种方法基本上做相同的事情,区别在于第二种方法已经在MockMvc中具有基本身份验证,这就是为什么您必须使用secure = false的原因
  3. 来自文档:

默认情况下,使用@WebMvcTest注释的测试还将自动配置 Spring Security和MockMvc(包括HtmlUnit WebClient和Selenium WebDriver支持)。要更精细地控制MockMVC,可以使用@AutoConfigureMockMvc注释。


5

我不确定这是否直接相关,但是有一个未解决的问题,如果使用spring boot和@WebMvcTest,那么您的自定义@EnableWebSecurity配置类将被忽略。该问题报告中提到了一些解决方法。我正在使用:

@WebMvcTest(includeFilters = @Filter(classes = EnableWebSecurity.class))

0

我不知道这是不是正确的方法,但我可以通过以下方式禁用配置类

@WebMvcTest(ProductController.class)
@ContextConfiguration(classes = ProductController.class)
public class ProductControllerTest {
  @Autowired
  private MockMvc mockMvc;

  @MockBean
  private ProductService productServiceMock;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接