spring-bootのweb-apiのintegration testでMockServerを使用する。
ソースコード
build.gradle
springとの連携用のmockserver-spring-test-listener-no-dependencies
の依存性を追加する。
plugins { id 'org.springframework.boot' version '2.6.6' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.mock-server:mockserver-spring-test-listener-no-dependencies:5.13.2' } tasks.named('test') { useJUnitPlatform() }
外部アクセスを伴う適当なrest-apiを作成する。
import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @SpringBootApplication() public class SampleWireMockApplication { @Value("${sample.remote.path}") String path; @RequestMapping("/sample/{key}") public String sample(@PathVariable String key) { RestTemplate template = new RestTemplate(); String result = template.getForObject(path + "/sample-api/" + key, String.class); return result; } public static void main(String[] args) { SpringApplication.run(SampleWireMockApplication.class, args); } }
プロパティファイルに外部アクセス先URLを持つ。
server.port=8081 sample.remote.path=http://example.com:12345
テストコードを作成する。
import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Map; import org.junit.jupiter.api.Test; import org.mockserver.client.MockServerClient; import org.mockserver.model.Header; import org.mockserver.model.HttpRequest; import org.mockserver.model.HttpResponse; import org.mockserver.springtest.MockServerTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.server.LocalServerPort; @SpringBootTest(properties = { "sample.remote.path=${server.url}" }, webEnvironment = WebEnvironment.RANDOM_PORT) @MockServerTest("server.url=http://localhost:${mockServerPort}") public class ApplicationTest { @LocalServerPort int serverPort; @Autowired TestRestTemplate template; MockServerClient mockServerClient; @Test void test() { mockServerClient .when(HttpRequest .request() .withMethod("GET") .withPath("/sample-api/key123")) .respond(HttpResponse .response() .withStatusCode(200) .withHeader( new Header("Content-Type", "application/json; charset=utf-8")) .withBody(""" { "sample-id": "id12345", "sample-value": "value" } """)); Map<String, String> actual = template.getForObject("http://localhost:" + serverPort + "/sample/key123", Map.class); Map<String, String> expected = Map.of("sample-id", "id12345", "sample-value", "value"); assertEquals(expected, actual); } }
webEnvironment = WebEnvironment.RANDOM_PORT
でランダムポートでこのapiが起動する。@MockServerTest
でspring連携が有効になりMockServerClient
フィールドを宣言すれば使用可能になる。@MockServerTest
のserver.url=http://localhost:${mockServerPort}
でmock-serverのURLを指定できる。@SpringBootTest
のproperties
で外部アクセスURLのプロパティをmock-serverのURLで上書きする。mockServerClient.when...
でモックの定義をする。TestRestTemplate
はRestTemplate
でも構わない。これからはWebTestClient
が主流になるかも?- assertEqualsはサンプルコードなので簡易にMapでの検証にした。実際にはrecordとかデータ保持クラスに詰め替えたりしてから検証、になると思われる。