17
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

◆ Spring Boot MockMVCを使った単体テスト

Posted at

★ はじめに

私はクラス名・メソッド名・変数名を考えるのがとても苦手です。
本来はtargetとなるメソッド名_結果や項番となるようにつけるのが望ましいのでしょうが、
仕様書とテストクラスは項番やNo.でマッピングしがちなので、だいたい「test001」のようにつけることが多いです。

今回は前回までに作成したControllerクラスのテストを実施してみます。

★ MockMVC

Spring testで提供されている機能。
Controllerのリクエスト~レスポンスまでの一連の流れが簡単に確認できる。

★ 実装内容

build.gradle

テストでMockMVCを使用するため、build.gradleに以下のように記述を追加。

build.gradle
dependencies {
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Controller/Service

ControllerやServiceについては以下記事よりほぼ変更なし。
◆ Spring Boot+MyBatis+PostgreSQL DB接続①

RestApiControllerTest.java(テストクラス)

RestApiControllerTest.java
package com.example.sample.app.controller;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import com.example.sample.app.domain.service.PersonService;
import com.example.sample.domain.entity.Person;
import com.fasterxml.jackson.databind.ObjectMapper;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RestApiControllerTest {

    MockMvc mockMvc;

    @InjectMocks
    RestApiController controller;

    @Test
    public void test001() {
        // パラメータのID
        Integer id = 10;

        // PersonServiceのMockを設定
        Person person = new Person();
        person.setId(id);
        person.setName("ほげみ");
        person.setAge(14);
        person.setHobby("パンケーキ屋さん巡り");

        PersonService mockService = mock(PersonService.class);
        when(mockService.findById(id)).thenReturn(person);

        Person expected = person;

        controller = new RestApiController();
        controller.personService = mockService;

        this.mockMvc = MockMvcBuilders
            .standaloneSetup(controller)
            .build();

        MockHttpServletRequestBuilder getRequest =
                MockMvcRequestBuilders.get("/api/sample/getPerson/" + id);

        try {
            MvcResult result = mockMvc.perform(getRequest)
                    .andDo(print())
                    .andExpect(status().isOk())
                    .andReturn();

            ObjectMapper mapper = new ObjectMapper();
            Person actual = mapper.readValue(result.getResponse().getContentAsString(), Person.class);

            assertEquals(expected.getId(), actual.getId());
            assertEquals(expected.getName(), actual.getName());
            assertEquals(expected.getAge(), actual.getAge());
            assertEquals(expected.getHobby(), actual.getHobby());

        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }
}

まずPersonServiceのMockを作成する。今回はMockitoを使用します。
Serviceのレスポンスをそのまま返却するという結構手抜きなAPIなので(処理結果とかエラーコードとかエラー事由とか入れればよかったかも)、イコールassertしたときの予想値となります。

リクエストを作成し、performで投げています。
今回はGETのテストのため、MockMvcRequestBuilders.get()と中にURLを設定。POSTの場合はpost()

.andExpect(status().isOk())でHTTPステータスが成功であることの検証を実施。
print()でコンソール上にリクエストやレスポンスなどの情報を出力してくれる。これけっこう感動しました。
ちなみに出力結果はこんな感じ。

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /api/sample/getPerson/10
       Parameters = {}
          Headers = []
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = com.example.sample.app.controller.RestApiController
           Method = public com.example.sample.domain.entity.Person com.example.sample.app.controller.RestApiController.getPerson(java.lang.Integer)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"application/json;charset=UTF-8"]
     Content type = application/json;charset=UTF-8
             Body = {"id":10,"name":"ほげみ","age":14,"hobby":"パンケーキ屋さん巡り"}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

実行後はmapperでResponse値を変換してassertで値の検証しています。

★ おわりに

ばばばーって書いたテストコードなのであんまりきれいじゃないなって記事を書きながら思いました。
あとせっかくだからPOSTで送った時の確認もしてみたい。

そして前回の続きのDB接続②はたぶん次で実施。

17
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?