きり丸の技術日記

技術・エンジニアのイベント・資格等はこちらにまとめる予定です

SpringSecurityが導入されているControllerをWebMvcTestでテストする【SpringBoot】

以前にControllerをテストする記事を書きました。しかし、SpringBootTestの使い方しか分からなかったので、WebMvcTestのやり方を理解していませんでした。

ですが、ToshiakiMaki@makingさんのサポートにより、なんとかWebMvcTestでのテストができるようになったので記事にします。

twitter.com

ゴール

  • Spring Securityがある状態でControllerのテストを行う
  • WebMvcTestでテストを行う

環境

  • Java
    • 15
  • org.springframework.boot:spring-boot-starter-Web
    • 2.4.0
  • org.springframework.boot:spring-boot-starter-test
    • 2.4.0
  • org.springframework.boot:spring-boot-starter-security
    • 2.4.0
  • org.springframework.security:spring-security-test
    • 5.4.1
  • lombok

テストクラスを準備する

WebMvcTestを使用します。アノテーションの変数のcontrollersにテスト対象のコントローラを指定してください。

テストでHTTP通信を行うために、mockMvcを@Autowiredでインジェクションします。

MockBeanはテスト対象のクラスにモックをインジェクションするために使用します。純粋なコントローラのみのテストを行いたいので、テスト対象以外のクラスをモックしています。

TestSecurityContextHolder.setAuthenticationに値を設定することで、BASIC認証がされている状態でテストを行えます。前回の記事ではこのBASIC認証が上手くいっていなかったです。

AuthTargetUserクラスはSpringSecurityを拡張した際に使用した自作クラスです。ですので、こちらにクラスに関しては参考になりませんので、注意してください。

@WebMvcTest(controllers = IndexController.class)
class IndexController2Tests {
  @Autowired
  private MockMvc mockMvc;

  @MockBean
  private TodoRepository todoRepository;


  @BeforeEach
  void setup() {
    AuthTargetUser user = new AuthTargetUser(new User("user", "pass", Collections.emptyList()));
    Authentication authentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
    TestSecurityContextHolder.setAuthentication(authentication);
  }
}

GETをテストする

GETの場合、通常のControllerのテストと同等のやりで大丈夫です。たぶん。

  @Test
  void test_01() throws Exception {
    mockMvc.perform(MockMvcRequestBuilders.get("/"))
        // レスポンスのステータスコードが200であることを検証する
        .andExpect(status().isOk())
        .andExpect(view().name("index"))
        .andExpect(model().attribute("todos", Collections.EMPTY_LIST))
    ;
  }

POSTをテストする

デフォルトのSpringSercurityを導入していると、CSRFトークンが必要です。試してはいませんが、CSRFが不要な設定にしていれば、特にテストは不要だと思います。

他にもSpringSecurityの設定を追加している場合は、withで必要な情報を渡す必要があります。

    @Test
    void test_01() throws Exception {
      mockMvc.perform(MockMvcRequestBuilders.post("/")
              .with(csrf()) // CSRFのトークン
          .param("add", "add")
          .param("id", "123")
          .param("userId", "user")
          .param("action", "actionする")
      )
          .andExpect(status().isFound());
    }

ソースコード

github.com

終わりに

SpringSecurityに不慣れなこともあり、ToshiakiMaki@makingさんのサポートがあっても解決に時間がかかってしまいました。

素直に英語を読めればいいんですけど、上手く読めないと解決まで時間かかってしまいますね…。

なんにせよ、WebMvcTestでのテストができるようになったので、私は満足です。

ToshiakiMaki@makingさん、ありがとうございました。


この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。

類似記事

きり丸アドベントカレンダー2020 adventar.org

【SpringBoot】Controllerのテストを行う(Not RestController) nainaistar.hatenablog.com

f:id:nainaistar:20201109133010p:plain