♨️
Spring Boot+JUnit5+Spring SecurityでControllerのテストをしてハマったポイント
Spring Bootを使ってREST APIを構築していたところ、Controllerのテストでハマったのでその解決策を書きました。
テスト実行時にNullPointerになる
原因
Controllerのテストにはテストクラスに@SpringBootTest
と@AutoConfigureMockMvc
アノテーションが必要でした。
GoodsControllerTest.java
@SpringBootTest
@AutoConfigureMockMvc
public GoodsControllerClass {
...
}
もしくは@WebMvcTest
を使います。
GoodsControllerTest.java
@WebMvcTest
class GoodsControllerTest {
...
}
アノテーションの違いについて
SpringBootのJavadocを確認すると、@WebMvcTest
を使った場合は以下のようになるようです。
- MVCに関連する設定のみを適用する(@Controller, @ControllerAdvice等)
- @Component, @Service, @Repositoryは除く
- Spring SecurityやMockMvcは設定してくれる
- Controller内で使うものは@MockBean等を使う必要がある
必要なものだけ、テスト時に設定してくれるアノテーションのため、ControllerやService, Repositoryを通しての結合テストがしたい場合は
@SpringBootTest
と@AutoConfigureMockMvc
をあわせて使う必要があります。
なので、Controllerの単体テストであれば@WebMvcTest
で良いです。というか、
テスト時に必要な設定も少なくできる分、単体テストの実行速度も向上できると考えられるので
その点でも単体テストでは@WebMvcTest
を使うほうがベターな気がします。
MockMvcでのリクエストが401になってしまう
MockHttpServletRequest:
HTTP Method = GET
Request URI = /api/items
Parameters = {}
Headers = []
Body = null
Session Attrs = {SPRING_SECURITY_SAVED_REQUEST=DefaultSavedRequest [http://localhost/api/items]}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 401
Error message = Unauthorized
Headers = [WWW-Authenticate:"Basic realm="Realm"", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
原因
Spring Securityはデフォルトだとログインページ以外、アクセスに認証が必要な設定になっているようです。
【Spring Security はじめました 】#1 導入
検証:実際に画面からアクセスしてみるとログイン画面に戻される
xxxApplication.java(mainクラスがあるやつ)と同じ階層にWebSecurityConfigurerAdapter
を継承したクラスを作成し、認証なしでアクセスできるページを設定します。
※import文省略
WebSecurityConfig.java
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/items").permitAll().anyRequest().authenticated();
}
}
これでテストを走らせると無事200でステータスが返ってくるようになりました。
Discussion