web-dev-qa-db-ja.com

Spring Boot 1.4 MVCテストで@WebMvcTestを使用してMockMvcをセットアップする

新しいSpring Boot 1.4 _@WebMvcTest_でさまざまな方法でMockMVcをセットアップするための作業コードはほとんどありません。 standaloneSetupアプローチを理解しています。私が知りたいのは、MockMvcからWebApplicationContextまでの設定と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 AP​​Iドキュメントによると、デフォルトでは、@ WebMvcTestアノテーションが付けられたテストは、Spring SecurityとMockMvcを自動構成します。そのため、ここでは401 Unauthorizedステータスコードが必要ですが、テストは200ステータスコードで合格します。

次に、MockMvcの自動配線を試みましたが、@AutoConfigureMockMvc(secure=false)を追加するか_@WebMvcTest_アノテーションを更新してセキュリティを無効にしない限り、テストは401 Unauthorizedステータスコードで失敗します。

_@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. MockMvcが自動配線したときに、コードスニペット1が401 Unauthorizedステータスコードエラーを報告しなかった理由。また、公式ドキュメントの内容を繰り返しますデフォルトでは、@ WebMvcTestアノテーションが付けられたテストは、Spring SecurityとMockMvcも自動構成します。しかし、この場合は表示されます_@WebMvcTest_は、Spring Securityの自動設定とは関係ありません(コードスニペット1が401エラーなしで渡されるため)。最後に、MockMvcの設定方法を説明します。私はここで正しいですか?

  2. 両方のアプローチの違い/目的は何ですか?

  3. @AutoConfigureMockMvc(secure=false)を介したセキュリティの無効化は、@WebMvcTest(controllers = IndexController.class, secure = false)を介した無効化とどのように異なりますか。どのアプローチが推奨されますか、それをいつ(またはどこで)使用しますか?

16
user2693135

私も同様の問題に遭遇します。 @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")));
    }

}
9
UmitYeldan

Githubのこの問題によると

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

@WebMvcTestはデフォルトで自動設定します。spring-security-testがクラスパスにある場合の基本認証

質問に答える:

  1. コードスニペット1では、テストクラスにMockMvcを挿入していません。setupメソッドのビルダーで.apply(springSecurity())を追加する必要があります。 1)
  2. 両方のアプローチは基本的に同じことを行いますが、違いは、2つ目は既にMockMvcに基本認証が付属していることです。そのため、secure = falseを使用する必要があります。
  3. ドキュメントから:

デフォルトでは、@ WebMvcTestアノテーションが付けられたテストは、Spring SecurityおよびMockMvcを自動構成します(HtmlUnit WebClientおよびSelenium WebDriverのサポートを含む)。 MockMVCのよりきめ細かい制御には、@ AutoConfigureMockMvcアノテーションを使用できます。

6
Marco Prado

これが直接関係するかどうかはわかりませんが、 顕著なバグ があります。ここで、スプリングブーツと@WebMvcTest、カスタム@EnableWebSecurity構成クラスは無視されます。いくつかの回避策がバグレポートに記載されています。私は使用しています:

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