스프링 클라우드 컨트랙트 공식 레퍼런스를 한글로 번역한 문서입니다.
전체 목차는 여기에 있습니다.
Spring Cloud Contract WireMock 모듈을 이용하면 스프링 부트 애플리케이션에서 WireMock을 사용할 수 있다. 자세한 내용은 Spring Cloud Contract 레포지토리에 있는 samples 폴더를 참고해라.
스프링 부트 애플리케이션에서 임베디드 톰캣을 사용하고 있다면 (spring-boot-starter-web
의 기본 동작), 클래스패스에 spring-cloud-starter-contract-stub-runner
를 추가하고 테스트 코드에 @AutoConfigureWireMock
을 선언해라. 그러면 Wiremock이 스텁stub 서버로 실행되며, 테스트 코드 내에서 Java API를 사용하거나 미리 정의해둔 JSON을 이용해 스텁stub의 동작 방식을 등록할 수 있다.
스텁stub 서버를 다른 포트에서 시작하고 싶다면, (예를 들어) @AutoConfigureWireMock(port=9999)
를 사용해라. 랜덤 포트를 사용하고 싶다면 0
으로 설정하면 된다. 스텁stub 서버의 포트는 wiremock.server.port
프로퍼티를 통해 테스트 애플리케이션 컨텍스트에 바인딩된다. @AutoConfigureWireMock
을 사용하면 테스트 애플리케이션 컨텍스트에 WiremockConfiguration
타입 빈이 추가되며, 이 빈은 동일한 컨텍스트를 가진 메소드와 클래스에 재사용한다. Spring 통합 테스트에서도 마찬가지다. 그 외에도, 테스트 코드에서 WireMockServer
타입 빈을 주입받을 수 있다. 등록된 WireMock 서버는 각 테스트 클래스를 실행한 뒤에 리셋된다. 각 테스트 메소드를 실행한 뒤에 매핑 정보를 리셋해야 한다면, wiremock.reset-mappings-after-each-test
프로퍼티를 true
로 설정해라.
목차
- 3.7.1. Stub 자동으로 등록하기
- 3.7.2. 파일로 Stub body 정의하기
- 3.7.3. 또 다른 방법: JUnit Rules 이용하기
- 3.7.4. RestTemplate의 SSL 검증 비활성화하기
- 3.7.5. WireMock과 Spring MVC Mock
3.7.1. Registering Stubs Automatically
@AutoConfigureWireMock
을 사용하면 파일 시스템이나 클래스패스에 있는 (디폴트로는 file:src/test/resources/mappings
에서) WireMock JSON 스텁stub을 등록한다. 이 위치는 어노테이션의 stubs
속성을 통해 커스텀할 수 있다. 여기에는 Ant 스타일의 리소스 패턴이나 디렉토리를 지정한다. 디렉토리를 지정하면 해당 디렉토리에 있는 ***/**.json
을 등록한다. 다음은 그 예시를 보여준다:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureWireMock(stubs="classpath:/stubs")
public class WiremockImportApplicationTests {
@Autowired
private Service service;
@Test
public void contextLoads() throws Exception {
assertThat(this.service.go()).isEqualTo("Hello World!");
}
}
사실 WireMock은
stubs
속성으로 커스텀한 위치뿐만 아니라, 항상src/test/resources/mappings
에 있는 매핑 정보도 함께 로드한다. 이 동작을 변경하려면 다음 섹션에서 설명하는 파일 루트 정보도 변경하면 된다.
참고로,
stubs
에 있는 매핑 정보는 Wiremock의 “디폴트 매핑”으로 간주하지 않으며, 테스트 중에com.github.tomakehurst.wiremock.client.WireMock.resetToDefaultMappings
를 호출해도stubs
에 위치한 매핑 정보는 포함되지 않는다. 반면,org.springframework.cloud.contract.wiremock.WireMockTestExecutionListener
는 모든 테스트 클래스 실행을 마친 후에, 그리고 설정에 따라 (wiremock.reset-mappings-after-each-test
프로퍼티로 관리한다) 모든 테스트 메소드 실행을 마친 후에 매핑 정보를 리셋한다.
Spring Cloud Contract의 디폴트 스텁stub jar를 사용 중이라면, /META-INF/group-id/artifact-id/versions/mappings/
폴더에 스텁stub을 저장한다. 임베딩한 모든 JAR 상에서 이곳에 위치한 스텁stub을 전부 등록하고 싶다면, 다음 구문을 사용하면 된다:
@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF...
3.7.2. Using Files to Specify the Stub Bodies
WireMock은 클래스패스나 파일 시스템에 있는 파일에서 응답 body를 읽어올 수 있다. 파일 시스템을 사용할 땐 JSON DSL 응답에 (말 그대로) body
를 바로 정의하는 대신, bodyFileName
을 정의한다. 이때 파일은 루트 디렉토리를 기준으로 리졸브한다 (디폴트는 src/test/resources/__files
). 이 위치를 커스텀하려면 @AutoConfigureWireMock
어노테이션의 files
속성에 원하는 상위 디렉토리를 설정하면 된다 (즉, __files
는 하위 디렉토리다). Spring 리소스 표기법을 사용해 file:…
또는 classpath:…
위치를 참조할 수도 있다. 일반 URL은 지원하지 않는다. 값은 여러 개 지정할 수 있으며, 이 경우 WireMock은 응답 body를 찾을 때 존재하는 첫 번째 파일을 리졸브한다.
files
루트를 설정하면 자동 로드하는 스텁stub에도 영향을 미친다. 스텁stub을 자동으로 로드할 땐 루트 경로 아래mappings
라는 하위 디렉토리에서 가져오기 때문이다.
files
의 값을 변경해도stubs
속성으로 명시한 곳에서 스텁stub을 로드하는 동작에는 영향을 미치지 않는다.
3.7.3. Alternative: Using JUnit Rules
좀더 일반적인 환경에선 JUnit @Rules
를 사용해 WireMock 서버를 시작하고 중지할 수 있다. 이땐 다음 예시에서 처럼, WireMockSpring
클래스를 활용해 Options
인스턴스를 가져오면 된다:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class WiremockForDocsClassRuleTests {
// Start WireMock on some dynamic port
// for some reason `dynamicPort()` is not working properly
public static WireMockServer wiremock = new WireMockServer(WireMockSpring.options().dynamicPort());
@BeforeAll
static void setupClass() {
wiremock.start();
}
@AfterEach
void after() {
wiremock.resetAll();
}
@AfterAll
static void clean() {
wiremock.shutdown();
}
// A service that calls out over HTTP to wiremock's port
@Autowired
private Service service;
@BeforeEach
public void setup() {
this.service.setBase("http://localhost:" + wiremock.port());
}
// Using the WireMock APIs in the normal way:
@Test
public void contextLoads() throws Exception {
// Stubbing WireMock
wiremock.stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
// We're asserting if WireMock responded properly
assertThat(this.service.go()).isEqualTo("Hello World!");
}
}
@ClassRule
은 이 클래스에 있는 모든 메소드를 실행한 후에 서버를 종료한다는 뜻이다.
3.7.4. Relaxed SSL Validation for Rest Template
WireMock을 사용하면 https
프로토콜을 사용하는 서버에도 스텁stub을 적용할 수 있다. 애플리케이션 통합 테스트에서 https 서버의 스텁stub과 연결하다보면, SSL 인증서가 유효하지 않다는 것을 깨닫게 될 거다 (자체 설치 인증서와 관련된 일반적인 이슈). 클라이언트가 http
를 사용하도록 설정할 수 있으면 가장 좋다. 하지만 이 방법이 불가능하다면, 스프링을 이용해 SSL 유효성 검사와 관련된 에러를 무시하는 HTTP 클라이언트를 구성하면 된다 (물론 테스트 환경에서만 이렇게 해야 한다).
가장 쉬운 방법은, 다음 예제와 같이 애플리케이션에서 스프링 부트의 RestTemplateBuilder
를 사용하는 거다:
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
콜백을 통해 RestTemplateBuilder
가 전달되기 때문에 직접 초기화할 수 있다. 여기에서 클라이언트에 SSL 유효성 검사 관련 설정을 추가하면 된다. 사실 @AutoConfigureWireMock
어노테이션이나 stub runner를 사용한다면 테스트에 자동으로 세팅될 거다. JUnit @Rule
을 사용 중이라면, 다음 예제와 같이 @AutoConfigureHttpClient
어노테이션도 추가해야 한다:
@RunWith(SpringRunner.class)
@SpringBootTest("app.baseUrl=https://localhost:6443")
@AutoConfigureHttpClient
public class WiremockHttpsServerApplicationTests {
@ClassRule
public static WireMockClassRule wiremock = new WireMockClassRule(
WireMockSpring.options().httpsPort(6443));
...
}
spring-boot-starter-test
를 사용하는 경우, 클래스패스에 Apache HTTP 클라이언트가 있다면, RestTemplateBuilder
에서 이를 확인해 SSL 관련 에러를 무시하도록 설정한다. 디폴트 java.net
클라이언트를 사용한다면 이 어노테이션이 필요하지 않다 (사용해도 상관 없다). 현재 다른 클라이언트에 대한 지원은 없지만 향후 릴리즈에 추가될 수 있다.
커스텀 RestTemplateBuilder
를 비활성화하려면 wiremock.rest-template-ssl-enabled
프로퍼티를 false
로 설정해라.
3.7.5. WireMock and Spring MVC Mocks
Spring Cloud Contract는 WireMock의 스텁stub JSON을 스프링 MockRestServiceServer
로 로드할 수 있는 편의 클래스를 제공한다. 다음 예시를 참고해라:
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class WiremockForDocsMockServerApplicationTests {
@Autowired
private RestTemplate restTemplate;
@Autowired
private Service service;
@Test
public void contextLoads() throws Exception {
// will read stubs classpath
MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate)
.baseUrl("https://example.org").stubs("classpath:/stubs/resource.json")
.build();
// We're asserting if WireMock responded properly
assertThat(this.service.go()).isEqualTo("Hello World");
server.verify();
}
}
mock을 호출할 때마다 baseUrl
값이 추가되며, stubs()
메소드는 메소드 인자로 스텁stub 경로의 리소스 패턴을 받는다. 위 예제에서는 /stubs/resource.json
에 정의되어 있는 스텁stub을 mock 서버에 로드한다. RestTemplate
이 example.org/
에 방문하라는 요청을 받으면, 이 URL에 지정된 응답을 가져온다. 스텁stub 패턴은 여러 개 지정할 수 있으며, 디렉토리(하위 디렉토리까지 포함한 디렉토리 내 모든 .json
파일), 고정 파일명(위 예제에서 사용), Ant 스타일 패턴을 사용할 수 있다. JSON 포맷은 일반적인 WireMock 포맷으로, WireMock 웹사이트에서 확인할 수 있다.
현재 Spring Cloud Contract Verifier는 스프링 부트 임베디드 서버로 Tomcat, Jetty, Undertow를 지원하며, WireMock 자체는 Jetty의 특정 버전(현재 9.2)을 “네이티브”로 지원한다. 네이티브 Jetty를 사용하려면 네이티브 Wiremock 의존성을 추가하고 스프링 부트 컨테이너(사용 중이라면)를 제외시켜야 한다.
Next :
Build Tools
스프링 클라우드 컨트랙트의 테스트 빌드 툴
전체 목차는 여기에 있습니다.