Closed8

SpringBoot + JUnitでREST APIのテストをする

ぶるーぶるー

NullPointerになる

java.lang.NullPointerException
	at captain.blue210.studyfornetsuperbackend.presentation.api.controller.goods.GoodsControllerTest.testGetAllItems(GoodsControllerTest.java:27)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
<省略>
ぶるーぶるー

Controllerのテストにはテストクラスに@SpringBootTestアノテーションが必要

つけて実行すると、エラー内容が変わった

2021-01-17 21:02:38.579 ERROR 38167 --- [           main] o.s.test.context.TestContextManager      : Caught exception while allowing TestExecutionListener [org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@6da21078] to prepare test instance [captain.blue210.studyfornetsuperbackend.presentation.api.controller.goods.GoodsControllerTest@72725ee1]

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'captain.blue210.studyfornetsuperbackend.presentation.api.controller.goods.GoodsControllerTest': Unsatisfied dependency expressed through field 'mock'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.test.web.servlet.MockMvc' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ~[spring-beans-5.3.2.jar:5.3.2]
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.2.jar:5.3.2]
<省略>
ぶるーぶるー

NoSuchBeanDefinitionExceptionというものがでているらしい。

これを調べると、@Componentのつけ忘れに気づく。
つけて再度実行したがまだ実行に失敗する

ぶるーぶるー

テストクラスのアノテーション指定が不足していたっぽい。
以下を付与したらテスト自体はできた

GoodsControllerTest.java
@SpringBootTest
@AutoConfigureMockMvc
public GoodsControllerClass {
...
}

もしくは、

GoodsControllerTest.java
@WebMvcTest
class GoodsControllerTest {
...
}
ぶるーぶるー

テスト自体は実行されるが、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 = []
ぶるーぶるー

@WithMockUserを使うと、ステータスは200になった。
SecurityConfigの設定すれば、上記は不要?

ぶるーぶるー

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でステータスが返ってくる

このスクラップは2021/01/18にクローズされました