2015年7月1日水曜日

Spring で MockMVC を使ってテストしてみる

概要

Spring Framework には End to End の のテストを実現するためにMockMvcという仕組みが存在しています
簡単にいうとAPIをコールしてその結果を評価するという一連の流れをテストすることができます

環境

  • Mac OS X 10.10.3
  • Eclipse Luna 4.4.1
  • Spring Framework 4.1.6
  • Spring Tool Suite 3.6.4
  • Java 1.8.0_31
  • Maven 3.2.1

サンプルプロジェクト作成

過去の記事を参考に作成してください
Spring Framework のバージョンが最新でない場合は pom.xml 「org.springframework-version」のバージョン記載部分を最新のバージョンに変更してください

Spring-Test のライブラリを追加する

pom.xmlspring-testのライブラリを追加します

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
   <version>${org.springframework-version}</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
</dependency>

junitを定義するところが既にある場合でもバージョンが4.9未満である場合は4.9以上にしてください
javax.servletを読み込んでいますが、デフォルトだと読み込んでいるサーブレットのバージョンが2.5でこれだとCaused by: java.lang.ClassNotFoundException: javax.servlet.SessionCookieConfigと言われてテストが失敗するので 3.0 系のバージョンを読み込みます

テストコードの作成

src/test/java/test/sample/MockMvcSampleTest.javaにテストコードを作成していきます
STSでプロジェクトを作成するとテスト用のコードは何も作成されないので、適当にテスト用のクラスファイルを作成しましょう
作成したらMockMVCを使うための定義を記載します

package com.sample;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@WebAppConfiguration
public class MockMvcSampleTest {

    @Autowired
    private WebApplicationContext wac;

    protected MockMvc mockMvc;

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

    @Test
    public void sampleTest() throws Exception {
        this.mockMvc.perform(get("/")).andExpect(status().isOk());
    }
}

いろいろ書いているので簡単にポイント説明します

クラスの定義の冒頭で3つのアノテーションを宣言しています

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@WebAppConfiguration

JUnit + MockMvc を使ってテストするために必要な記述です
詳細は正直自分もよくわかっていませんが

  • RunWithでランナーを選択して
  • ContextConfigurationでサーブレットの設定が記述されたコンテキストファイルを読み込んで
  • WebAppConfigurationでWebアプリをテストするための必要なコンテストに触れるようにしています

とにかく1つでも定義がかけるとエラーになるので必ず定義します

次にMockMvcのオブジェクトを定義する部分です

@Autowired
private WebApplicationContext wac;

protected MockMvc mockMvc;

MockMvcのオブジェクトを作成するのにWebApplicationContextが必要で、このオブジェクトは先程のアノテーション+@Autowiredすることで勝手に設定されるオブジェクトです
この2つのオブジェクトを使って、サンプルのsetupメソッドにあるようにbuildするとMockMvcのオブジェクトが生成されます

最後にテストの方法です

this.mockMvc.perform(get("/")).andExpect(status().isOk());

ポイントはgetstatusというメソッドをimport文でstaticに読み込んでいる部分です
こうすることでテストを書く際にメソッドの呼び出しを直感的に行えます
performでコールするAPIのパスとHTTPメソッドを指定して、その結果をandExpectで評価する感じです
今回のテストの場合はレスポンスコードが20X系であることを確認するテストになっています

Tips

他のHTTPメソッドでコールしたい場合は

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;

こんな感じでimportして

this.mockMvc.perform(post("/")).andExpect(status().isMethodNotAllowed());

こんな感じでテストできます

リクエストヘッダを指定したい場合はperformの後に.header("key", "value")で指定できます

リクエストパラメータを指定したい場合はperformの後に.param("key", "value")で指定できます

(POSTやPUTの場合に)リクエストボディを設定したい場合はperformの後に.content("body_value")で指定できます

実行

STSで作成していれば自動的にMavenプロジェクトになっているのでmvn packageなどで実行すればライフサイクルの中にテストが含まれるので自動でテストされます
テストだけ個別で実行したい場合はmvn test-compile testなどとすれば実行されます

最後に

Spring Framework にはデフォルトで end to end のテスト方法が含まれているのでAPIサーバを作る場合には割りと簡単にテストが書けそうです
MockMvc を使わないテストも記述することもできるので、メソッド個別でテストしたい場合には別のテストメソッドを作成してテストするといいと思います
JUnitが使えるのでJUnitAssert等も使うことができます

次回はテスト時に Filter を通してテストする方法を紹介したいと思います

0 件のコメント:

コメントを投稿