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つの質問があります:
コンテキストで定義された{@linkServlet}または{@linkFilter} Beanは、埋め込まれたサーブレットコンテナに自動的に登録されます。
結果として、Spring Bootの自動構成の魔法のために、これが「正しく機能する」と(間違って?)期待しているので、セキュリティフィルターチェーンを手動で追加する必要はないと思いますか?
アドバイスをよろしくお願いします。
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マッピングを確立して、適切に追加する必要があることを意味します。これはエラーが発生しやすく、不要のようです。
私はモック[〜#〜] 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();
}
これを試しましたか?
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ですが、わかります。