Spring BootでMockitoでモックテスト
Spring BootでMockitoでモックテストを試したメモです。
Spring BootでMockitoを試してみました。
Mockito
Mockitoはjavaのモックライブラリです。
JUnit単体ではモックテストを行うことができないので、
モックライブラリを利用する必要があります。
モックを作成することで、メソッドの呼び出しの検証を行うことができます。
Mockitoでモックオブジェクトを作ってテストしてみようと思います。
使用する準備としてpom.xmlにmaven dependencyを追加します。
テストでしか使わないのでtestスコープに入れました。
pom.xml
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.2.7</version> <scope>test</scope> </dependency>
テスト対象
下記のようなPeopleServiceクラスを用意しました。
このクラスは外部サーバのAPIにアクセスして、データを取得するようなサービスクラスを想定してます。
PeopleService.java
package com.example.mockito.service; import lombok.AccessLevel; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.net.URI; import java.net.URISyntaxException; @Service public class PeopleService { @Autowired private RestTemplate restTemplate; static private final String HOST = "http://dummy-host.com:8080"; public People getPeople(String country) { String url = HOST + "/api/people/" + country; return restTemplate.getForObject(url, People.class); } public int postPeople(People people) { String url = HOST + "/api/people"; return restTemplate.postForObject(url, people, Integer.class); } public int putPeople(People people) throws URISyntaxException { String url = HOST + "/api/people"; URI uri = new URI(url); RequestEntity<People> requestEntity = RequestEntity .put(uri) .body(people); ResponseEntity<Integer> result = restTemplate.exchange(requestEntity, Integer.class); return result.getBody(); } public int deletePeople(String country) { String url = HOST + "/api/people/" + country; ResponseEntity<Integer> result = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Integer.class, country); return result.getBody(); } @Data @NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public static class People { String country; int year; int population; } }
getPeople()
Peopleオブジェクトを取得。
public People getPeople(String country) { String url = HOST + "/api/people/" + country; return restTemplate.getForObject(url, People.class); }
postPeople()
Peopleオブジェクトを登録。
public int postPeople(People people) { String url = HOST + "/api/people"; return restTemplate.postForObject(url, people, Integer.class); }
putPeople()
Peopleオブジェクトを更新。
public int putPeople(People people) throws URISyntaxException { String url = HOST + "/api/people"; URI uri = new URI(url); RequestEntity<People> requestEntity = RequestEntity .put(uri) .body(people); ResponseEntity<Integer> result = restTemplate.exchange(requestEntity, Integer.class); return result.getBody(); }
deletePeople()
Peopleオブジェクトを削除。
public int deletePeople(String country) { String url = HOST + "/api/people/" + country; ResponseEntity<Integer> result = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Integer.class, country); return result.getBody(); }
Mockitoによるスタブテスト
PeopleServiceで外部サーバのAPIコールをするのですが、
その外部サーバのAPIが出来ていない場合のスタブとして、
またはテスト用のスタブとしてMockitoを使ってスタブテストをしてみます。
(1) @RunWithアノテーションでMockitoJUnitRunner.classを指定することで、モックオブジェクトをインジェクトできます。
(2) @Mockでモックオブジェクトをインジェクトします。
(3) mock()メソッドを使用してモックオブジェクトを生成します。
@SpringBootTest @RunWith(MockitoJUnitRunner.class) // (1) public class PeopleServiceTest { @Mock // (2) PeopleService mockService; /* private PeopleService mockService; @Before public void before() { mockService = mock(PeopleService.class); // (3) } */ : : : }
getPeople()メソッドのテスト
(1) モックオブジェクトはそのままではすべてのスタブメソッドでnullを返します。
そのため、戻り値を定義してやる必要があります。
戻り値を定義するのは、when()メソッドで対象のスタブメソッド記述し、thenReturn()で戻り値を記述します。
Peopleオブジェクトを戻すように定義します。
(2) あとは普通にスタブメソッド呼び出しでテストできます。
(3) スタブメソッドが呼び出されたことを検証するには、verify()を使用します。
times(3)でgetPeople()が3回呼び出されたことを検証しています。
(4) never()でpostPeople()が呼び出されていないことを検証しています。
(5) Mockitoでは前置記法でも記述できます。
reset()で定義していたスタブメソッドの戻り値をリセットします。
(6) 前置記法ではdoReturn()で期待される値を記述して、その後にwhen()で対象のスタブメソッドを記述します。
@Test public void getPeopleTest() { String country = "japan"; People expected = new People(); expected.setCountry("japan"); expected.setYear(2001); expected.setPopulation(1_000_000); when(mockService.getPeople(country)).thenReturn(expected); // (1) // assert assertThat(mockService.getPeople(country).getCountry()).isEqualTo("japan"); // (2) assertThat(mockService.getPeople(country).getYear()).isEqualTo(2001); assertThat(mockService.getPeople(country).getPopulation()).isEqualTo(1_000_000); // verify verify(mockService, times(3)).getPeople(country); // (3) verify(mockService, never()).postPeople(new People()); // (4) // 前置記法 reset(mockService); // (5) doReturn(expected).when(mockService).getPeople(country); // (6) assertThat(mockService.getPeople(country).getCountry()).isEqualTo("japan"); assertThat(mockService.getPeople(country).getYear()).isEqualTo(2001); assertThat(mockService.getPeople(country).getPopulation()).isEqualTo(1_000_000); }
postPeople()のテスト
同様にスタブメソッドを定義してテストします。
@Test public void postPeopleTest() { People people = new People(); people.setCountry("japan"); people.setYear(2001); people.setPopulation(1_000_000); when(mockService.postPeople(people)).thenReturn(1); assertThat(mockService.postPeople(people)).isEqualTo(1); }
putPeople()のテスト
同様にスタブメソッドを定義してテストします。
@Test public void putPeopleTest() throws URISyntaxException { People people = new People(); people.setCountry("japan"); people.setYear(2001); people.setPopulation(1_000_000); when(mockService.putPeople(people)).thenReturn(1); assertThat(mockService.putPeople(people)).isEqualTo(1); }
deletePeople()のテスト
同様にスタブメソッドを定義してテストします。
@Test public void deletePeopleTest() { when(mockService.deletePeople("japan")).thenReturn(1); assertThat(mockService.deletePeople("japan")).isEqualTo(1); }
テストコード
今回のテストコードの全体です。
PeopleServiceTest.java
package com.example.mockito.service; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.boot.test.context.SpringBootTest; import java.net.URISyntaxException; import static com.example.mockito.service.PeopleService.*; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @SpringBootTest @RunWith(MockitoJUnitRunner.class) public class PeopleServiceTest { @Mock PeopleService mockService; // @Mock or mock() /* private PeopleService mockService; @Before public void before() { mockService = mock(PeopleService.class); } */ @Test public void getPeopleTest() { String country = "japan"; People expected = new People(); expected.setCountry("japan"); expected.setYear(2001); expected.setPopulation(1_000_000); when(mockService.getPeople(country)).thenReturn(expected); // assert assertThat(mockService.getPeople(country).getCountry()).isEqualTo("japan"); assertThat(mockService.getPeople(country).getYear()).isEqualTo(2001); assertThat(mockService.getPeople(country).getPopulation()).isEqualTo(1_000_000); // verify verify(mockService, times(3)).getPeople(country); verify(mockService, never()).postPeople(new People()); // 前置記法 reset(mockService); doReturn(expected).when(mockService).getPeople(country); assertThat(mockService.getPeople(country).getCountry()).isEqualTo("japan"); assertThat(mockService.getPeople(country).getYear()).isEqualTo(2001); assertThat(mockService.getPeople(country).getPopulation()).isEqualTo(1_000_000); } @Test public void postPeopleTest() { People people = new People(); people.setCountry("japan"); people.setYear(2001); people.setPopulation(1_000_000); when(mockService.postPeople(people)).thenReturn(1); assertThat(mockService.postPeople(people)).isEqualTo(1); } @Test public void putPeopleTest() throws URISyntaxException { People people = new People(); people.setCountry("japan"); people.setYear(2001); people.setPopulation(1_000_000); when(mockService.putPeople(people)).thenReturn(1); assertThat(mockService.putPeople(people)).isEqualTo(1); } @Test public void deletePeopleTest() { when(mockService.deletePeople("japan")).thenReturn(1); assertThat(mockService.deletePeople("japan")).isEqualTo(1); } }
ソースは一応あげときました。
終わり。