★ はじめに
私はクラス名・メソッド名・変数名を考えるのがとても苦手です。
本来はtargetとなるメソッド名_結果や項番となるようにつけるのが望ましいのでしょうが、
仕様書とテストクラスは項番やNo.でマッピングしがちなので、だいたい「test001」のようにつけることが多いです。
今回は前回までに作成したControllerクラスのテストを実施してみます。
★ MockMVC
Spring testで提供されている機能。
Controllerのリクエスト~レスポンスまでの一連の流れが簡単に確認できる。
★ 実装内容
build.gradle
テストでMockMVCを使用するため、build.gradleに以下のように記述を追加。
dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Controller/Service
ControllerやServiceについては以下記事よりほぼ変更なし。
◆ Spring Boot+MyBatis+PostgreSQL DB接続①
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接続②はたぶん次で実施。