1. 序章

ある種のWebリクエストを実行するアプリケーションをよく目にします。 この動作のテストに関しては、Springアプリでいくつかのオプションがあります。

I このクイックチュートリアルでは、RestTemplateを介してのみ実行されるこのような呼び出しをモックするいくつかの方法を見ていきます。

まず、人気のあるモックライブラリであるMockitoでテストします。 次に、Spring Testを使用します。これは、サーバーの相互作用を定義するための模擬サーバーを作成するメカニズムを提供します。

2. Mockitoを使用する

Mockitoを使用して、RestTemplateを完全にモックすることができます。 このアプローチを使用すると、サービスのテストは、モッキングを含む他のテストと同じくらい簡単になります。

単純なEmployeeServiceクラスがあり、HTTPを介して従業員の詳細を取得するとします。

@Service
public class EmployeeService {
    
    @Autowired
    private RestTemplate restTemplate;

    public Employee getEmployee(String id) {
	ResponseEntity resp = 
          restTemplate.getForEntity("http://localhost:8080/employee/" + id, Employee.class);
        
	return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null;
    }
}

次に、前のコードのテストを実装しましょう。

@ExtendWith(MockitoExtension.class)
public class EmployeeServiceTest {

    @Mock
    private RestTemplate restTemplate;

    @InjectMocks
    private EmployeeService empService = new EmployeeService();

    @Test
    public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
        Employee emp = new Employee(“E001”, "Eric Simmons");
        Mockito
          .when(restTemplate.getForEntity(
            “http://localhost:8080/employee/E001”, Employee.class))
          .thenReturn(new ResponseEntity(emp, HttpStatus.OK));

        Employee employee = empService.getEmployee(id);
        Assertions.assertEquals(emp, employee);
    }
}

上記のJUnitテストクラスでは、最初に@Mockアノテーションを使用してダミーのRestTemplateインスタンスを作成するようにMockitoに依頼しました。

次に、EmployeeServiceインスタンスに@InjectMocksの注釈を付けて、ダミーインスタンスを挿入しました。

最後に、テストメソッドでは、Mockitoのwhen/ thensupportを使用してモックの動作を定義しました。

3. スプリングテストの使用

Spring Testモジュールには、MockRestServiceServerという名前のモックサーバーが含まれています。このアプローチでは、RestTemplateインスタンスを介して特定のリクエストがディスパッチされたときに、特定のオブジェクトを返すようにサーバーを構成します。 さらに、すべての期待が満たされているかどうかに関係なく、そのサーバーインスタンスで verify()を実行できます。

MockRestServiceServer は、実際にはMockClientHttpRequestFactoryを使用してHTTPAPI呼び出しをインターセプトすることで機能します。 構成に基づいて、予想される要求と対応する応答のリストを作成します。 RestTemplate インスタンスがAPIを呼び出すと、期待値のリストでリクエストを検索し、対応するレスポンスを返します。

したがって、模擬応答を送信するために他のポートでHTTPサーバーを実行する必要がなくなります。

MockRestServiceServer を使用して、同じ getEmployee()の例の簡単なテストを作成しましょう。

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SpringTestConfig.class)
public class EmployeeServiceMockRestServiceServerUnitTest {

    @Autowired
    private EmployeeService empService;
    @Autowired
    private RestTemplate restTemplate;

    private MockRestServiceServer mockServer;
    private ObjectMapper mapper = new ObjectMapper();

    @BeforeEach
    public void init() {
        mockServer = MockRestServiceServer.createServer(restTemplate);
    }
    
    @Test                                                                                          
    public void givenMockingIsDoneByMockRestServiceServer_whenGetIsCalled_thenReturnsMockedObject()() {   
        Employee emp = new Employee("E001", "Eric Simmons");
        mockServer.expect(ExpectedCount.once(), 
          requestTo(new URI("http://localhost:8080/employee/E001")))
          .andExpect(method(HttpMethod.GET))
          .andRespond(withStatus(HttpStatus.OK)
          .contentType(MediaType.APPLICATION_JSON)
          .body(mapper.writeValueAsString(emp))
        );                                   
                       
        Employee employee = empService.getEmployee(id);
        mockServer.verify();
        Assertions.assertEquals(emp, employee);                                                        
    }
}

前のスニペットでは、MockRestRequestMatchersおよびMockRestResponseCreatorsの静的メソッドを使用して、REST呼び出しの期待値と応答を明確で読みやすい方法で定義しました。

import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;      
import static org.springframework.test.web.client.response.MockRestResponseCreators.*;

テストクラスのRestTemplateは、EmployeeServiceクラスで使用されるインスタンスと同じである必要があることに注意してください。 これを確実にするために、Spring構成でRestTemplate Beanを定義し、テストと実装の両方でインスタンスを自動配線しました。

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

MockRestServiceServer を使用すると、統合テストを作成するときに非常に便利で、外部HTTP呼び出しをモックするだけで済みます。

4. 結論

この短い記事では、単体テストの作成中にHTTP経由で外部RESTAPI呼び出しをモックするためのいくつかの効果的なオプションについて説明しました。

上記の記事のソースコードは、GitHubから入手できます。