web-dev-qa-db-ja.com

MockMVCとの統合テストSpringBoot

MockMvcを使用してSpringBootアプリケーションをテストするのに問題があります。

私は次のテストクラスを持っています:

_@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {SpringConfiguration.class, SecurityConfiguration.class})
@IntegrationTest({"server.port=8080"})
@WebAppConfiguration
public class DemoTest {

@Autowired
private EmbeddedWebApplicationContext webApplicationContext;

private MockMvc mockMvc;

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

@Test
public void testGetAccountUnauthenticated() throws Exception {
    mockMvc.perform(get("/accounts/1").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isUnauthorized());
}
}
_

これにより、401ではなくHTTP 200になります。コンポーネントスキャンと自動構成を有効にしており、SecuityConfigurationクラスでスプリングセキュリティが次のように構成されています。

_@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity // required for use of @AuthenticationPrincipal in MVC controllers.
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
public void configure(WebSecurity web) {
    web.debug(true);
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    //set up authentication.
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().authenticated();
   // set up form login
}
}
_

RestTemplateを使用して_http://localhost:8080/accounts/1_にアクセスすると、期待される動作(HTTP 401)が得られます。

FilterChainProxyを自動配線し、WebApplicationContext.addFilters(filterChainProxy)メソッドを使用して手動でフィルターを追加することを提案する他の例(例: テスト用のSpring Bootセットアップセキュリティ )を見てきました。しかし、これは実際には失敗します(_org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.web.FilterChainProxy] found_)。

2つの質問があります:

  1. 挿入されたWebApplicationContextがSpringSecurityフィルターを自動的に使用しないのはなぜですか? FilterChainProxyを取得して手動で追加できたとしても、JavaDoc forEmbeddedWebApplicationContextは次のように述べています。

コンテキストで定義された{@linkServlet}または{@linkFilter} Beanは、埋め込まれたサーブレットコンテナに自動的に登録されます。

結果として、Spring Bootの自動構成の魔法のために、これが「正しく機能する」と(間違って?)期待しているので、セキュリティフィルターチェーンを手動で追加する必要はないと思いますか?

  1. アプリケーションコンテキストにFilterChainProxyがないのはなぜですか?繰り返しになりますが、AutoConfigurationに対する私の期待は正しくないかもしれませんが、これはコンテキスト構成の一部として構成されると思いました。

アドバイスをよろしくお願いします。


編集

  • FilterChainProxyが挿入されない理由は、構成をに設定しているためです。

    public void configure(WebSecurity web){web.debug(true); }

これにより、実際には代わりに_org.springframework.security.web.debug.DebugFilter_が構成されます。このデバッグ設定に関係なく、フィルターを取得する方法は次のとおりです。

_@Resource(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
private Filter securityFilter;
_

これを次のようにMockMvcBuilderに追加すると:

_MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilters(securityFilter)
_

その後、期待どおりに機能します。

しかし、MockMVCがフィルターを無視する理由はわかりません。これは、テストの結果に影響を与える可能性のある何かがフィルターで発生する可能性があるため、リクエストのテストにとって重要であると思われるためです。さらに、適切にテストするには、サーブレットコンテキストですべてのフィルターを検索し、それらの優先度/ URLマッピングを確立して、適切に追加する必要があることを意味します。これはエラーが発生しやすく、不要のようです。

14
David

私はモック[〜#〜] mvc [〜#〜]がおそらくSpring [〜#〜] mvc [〜#〜]とカスタムコードのテストに適していることに同意します@ dave-syerによってコメントされたコントローラー。したがって、カスタムコントローラーコードを使用してSpring MVCインフラストラクチャを同時にテストする場合(URLにマップされたコントローラーの正確性、入力オブジェクトと出力オブジェクトのマッピングと検証、標準コントローラー、コントローラー)は、のサーブレットコンテナー部分を利用せずにスタック、MockMVCはあなたのためにあります。

ただし、MockMVCにはフィルターを追加するメソッドもあるため、isは、説明されているタイプのテストにフィルターを使用できるように設計されています。フィルターがコントローラー内のコードに対して機能的な役割を果たす場合があり、それ以外の場合はMockMVCでテストできません。

そのすべての理論を念頭に置いて、Spring Bootの方法でフィルターをセットアップし、MockVMCで使用するためにテストで取得するテストのブート動作を模倣しようとしていました。これが私が使用することになったスニペットです。ブート動作をより正確に模倣するように拡張し、カスタムMockMVCBuilderに抽出することができます。

@Autowired
private WebApplicationContext wac;

private MockMvc mockMvc;

@Before
public void setUp() {
    Collection<Filter> filterCollection = wac.getBeansOfType(Filter.class).values();
    Filter[] filters = filterCollection.toArray(new Filter[filterCollection.size()]);
    mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilters(filters).build();
}
8
ynovytskyy

これを試しましたか?

import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;

...
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class AuthorizeTest {

    @Autowired
    private WebApplicationContext wac;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(wac)
                .apply(springSecurity())
                .build();
    }
    ...

}

私の場合は401ではなく403ですが、わかります。

0
WesternGun