【问题标题】:Setting up MockMvc with @WebMvcTest in Spring Boot 1.4 MVC Testing在 Spring Boot 1.4 MVC 测试中使用 @WebMvcTest 设置 MockMvc
【发布时间】:2016-11-05 05:00:39
【问题描述】:

我几乎没有工作代码可以使用新的 Spring Boot 1.4 @WebMvcTest 以不同的方式设置 MockMVc。我了解standaloneSetup 方法。我想知道的是设置MockMvcWebApplicationContext 和自动装配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 Unauthorized 状态码,但测试通过并显示 200 状态码。

接下来,我尝试自动连接MockMvc,但测试失败并显示 401 Unauthorized 状态码,除非我添加 @AutoConfigureMockMvc(secure=false) 或更新 @WebMvcTest 注释以禁用安全性:

@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. 为什么 Code sn-p 1 没有报告 401 Unauthorized 状态代码错误,而自动接线 MockMvc 报告了。还要重申官方文档所说的 默认情况下,使用 @WebMvcTest 注释的测试也将自动配置 Spring Security 和 MockMvc。 但是,在这种情况下,@WebMvcTest 似乎与自动配置无关Spring Security(因为代码片段 1 通过没有任何 401 错误)。最后归结为我如何设置MockMvc。我说的对吗?

  2. 这两种方法的区别/目标是什么?

  3. 通过@AutoConfigureMockMvc(secure=false) 禁用安全性与通过@WebMvcTest(controllers = IndexController.class, secure = false) 禁用安全性有何不同。哪个是首选方法或何时(或在何处)使用它们?

【问题讨论】:

    标签: spring-mvc spring-boot spring-mvc-test


    【解决方案1】:

    我不知道这是否正确,但我可以使用下面的方法禁用配置类

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

    【讨论】:

      【解决方案2】:

      我也遇到过类似的问题。 @WebMvcTest 自动使用基本身份验证配置 Spring Security,但我有一个扩展 WebSecurityConfigurerAdapter.WebSecurityConfig 类在这个类中,我禁用了基本身份验证并配置了令牌基础安全性。这意味着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")));
          }
      
      }
      

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

          根据github中的这个问题

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

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

          回答您的问题:

          1. 在代码 sn-p 1 中,您没有在测试类中注入 MockMvc,您应该在 setup 方法的 builder 中添加 .apply(springSecurity()),因此 spring 将使用基本配置(不是您的自定义安全配置(如果有)
          2. 这两种方法的作用基本相同,不同之处在于第二种方法已经在 MockMvc 中提供了基本身份验证,这就是您必须使用 secure=false 的原因
          3. 来自文档:

          默认情况下,使用 @WebMvcTest 注释的测试也会自动配置 Spring Security 和 MockMvc(包括对 HtmlUnit WebClient 的支持 和 Selenium WebDriver)。为了更细粒度地控制 MockMVC 可以使用@AutoConfigureMockMvc 注解。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-04-19
            • 1970-01-01
            • 2015-01-01
            • 2016-10-29
            • 2016-10-31
            • 2013-07-06
            • 2016-11-05
            相关资源
            最近更新 更多