토리맘의 한글라이즈 프로젝트 logo 토리맘의 한글라이즈 프로젝트

스프링 클라우드 컨트랙트 공식 레퍼런스를 한글로 번역한 문서입니다.

전체 목차는 여기에 있습니다.

목차


6.1. Adding the Maven Plugin

Spring Cloud Contract BOM을 추가하려면, pom.xml 파일에 아래 설정을 추가해라:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-dependencies</artifactId>
	<version>${spring-cloud-contract.version}</version>
	<type>pom</type>
	<scope>import</scope>
</dependency>

그 다음, 아래와 같이 메이븐 플러그인 Spring Cloud Contract Verifier를 추가한다:

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<version>${spring-cloud-contract.version}</version>
	<extensions>true</extensions>
	<configuration>
		<packageWithBaseClasses>com.example.fraud</packageWithBaseClasses>
	</configuration>
</plugin>

자세한 내용은 Spring Cloud Contract Maven Plugin 문서에서 확인할 수 있다.

간혹 사용하는 IDE에 관계없이, IDE의 클래스패스에 target/generated-test-source 폴더가 보이지 않을 때가 있다. 이 폴더가 항상 표시되도록 만들려면 pom.xml에 아래 설정을 추가하면 된다

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>build-helper-maven-plugin</artifactId>
	<executions>
		<execution>
			<id>add-source</id>
			<phase>generate-test-sources</phase>
			<goals>
				<goal>add-test-source</goal>
			</goals>
			<configuration>
				<sources>
					<source>${project.build.directory}/generated-test-sources/contracts/</source>
				</sources>
			</configuration>
		</execution>
	</executions>
</plugin>

6.2. Maven and Rest Assured 2.0

기본적으로 클래스패스에 Rest Assured 3.x가 추가된다. 이대신 Rest Assured 2.x를 사용하고 싶다면, 아래 보이는 것처럼 추가해줄 수 있다:

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <packageWithBaseClasses>com.example</packageWithBaseClasses>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-contract-verifier</artifactId>
            <version>${spring-cloud-contract.version}</version>
        </dependency>
        <dependency>
           <groupId>com.jayway.restassured</groupId>
           <artifactId>rest-assured</artifactId>
           <version>2.5.0</version>
           <scope>compile</scope>
        </dependency>
        <dependency>
           <groupId>com.jayway.restassured</groupId>
           <artifactId>spring-mock-mvc</artifactId>
           <version>2.5.0</version>
           <scope>compile</scope>
        </dependency>
    </dependencies>
</plugin>

<dependencies>
    <!-- all dependencies -->
    <!-- you can exclude rest-assured from spring-cloud-contract-verifier -->
    <dependency>
       <groupId>com.jayway.restassured</groupId>
       <artifactId>rest-assured</artifactId>
       <version>2.5.0</version>
       <scope>test</scope>
    </dependency>
    <dependency>
       <groupId>com.jayway.restassured</groupId>
       <artifactId>spring-mock-mvc</artifactId>
       <version>2.5.0</version>
       <scope>test</scope>
    </dependency>
</dependencies>

이렇게 설정해주면 플러그인에서 자동으로 클래스패스에 Rest Assured 2.x가 있는지 확인하고 그에 따라 import 구문을 수정한다.


6.3. Using Snapshot and Milestone Versions for Maven

스냅샷이나 마일스톤 버전을 사용하고 싶다면, pom.xml에 아래 설정을 추가해야 한다:

<repositories>
	<repository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</repository>
	<repository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</repository>
</repositories>
<pluginRepositories>
	<pluginRepository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</pluginRepository>
	<pluginRepository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</pluginRepository>
</pluginRepositories>

6.4. Adding stubs

Spring Cloud Contract Verifier는 기본적으로 src/test/resources/contracts 디렉토리에서 스텁stub을 찾는다. 스텁stub 정의가 담겨있는 디렉토리명을 클래스 이름으로 매핑하며, 각 스텁stub 정의는 하나의 테스트로 취급한다. 테스트 클래스 이름으로 사용할 디렉토리가 적어도 한 depth 이상 포함되어 있다고 가정한다. 여러 depth로 중첩된 디렉토리가 존재한다면, 마지막 디렉토리를 제외한 나머지는 패키지 이름으로 사용한다. 예를 들어 아래와 같은 구조를 사용한다면:

src/test/resources/contracts/myservice/shouldCreateUser.groovy
src/test/resources/contracts/myservice/shouldReturnUser.groovy

Spring Cloud Contract Verifier는 위와 같은 구조에선, 아래 두 개의 메소드를 가진 defaultBasePackage.MyService라는 테스트 클래스를 생성한다:


6.5. Run Plugin

플러그인 goal generateTestsgenerate-test-sources 단계에서 실행되도록 할당된다. 즉, 따로 뭘 해주지 않아도 빌드 프로세스에 포함된다. 테스트만 생성하고 싶다면 generateTests goal을 실행해라.

메이븐으로 스텁stub을 실행하려면, 다음과 같이 시스템 프로퍼티 spring.cloud.contract.verifier.stub으로 실행할 스텁을 지정해 run goal을 실행해라:

mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:run \
  -Dspring.cloud.contract.verifier.stubs="com.acme:service-name"

6.6. Configure plugin

디폴트 설정을 변경하고 싶다면, 다음과 같이 플러그인 정의나 execution 정의에 configuration 섹션을 추가해주면 된다:

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>convert</goal>
                <goal>generateStubs</goal>
                <goal>generateTests</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <basePackageForTests>org.springframework.cloud.verifier.twitter.place</basePackageForTests>
        <baseClassForTests>org.springframework.cloud.verifier.twitter.place.BaseMockMvcSpec</baseClassForTests>
    </configuration>
</plugin>

6.7. Configuration Options

명세contract 정의를 메이븐 레포지토리에서 다운받고 싶다면, 아래 옵션들을 사용할 수 있다:

스냅샷이 아닌 버전을 명시한 경우에만 캐시에 저장한다 (예를 들어 +1.0.0.BUILD-SNAPSHOT은 캐싱하지 않는다). 이 기능은 기본적으로 켜져있다.

메이븐 플러그인이 제공하는 실험적인 기능들도 사용해볼 수 있다:


6.8. Single Base Class for All Tests

MockMvc에서 Spring Cloud Contract Verifier를 사용하는 경우 (디폴트), 모든 자동 생성 인수 테스트acceptance test에서 사용할 베이스 specification을 생성해야 한다. 이 클래스에서 어떤 엔드포인트를 대상으로 테스트를 진행할지를 정의하면 된다. 그 방법은 다음 예제를 참고해라:

import org.mycompany.ExampleSpringController
import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc
import spock.lang.Specification

class MvcSpec extends Specification {
  def setup() {
   RestAssuredMockMvc.standaloneSetup(new ExampleSpringController())
  }
}

필요하다면, 다음과 같이 전체 컨텍스트를 세팅할 수도 있다:

import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
public abstract class BaseTestClass {

	@Autowired
	WebApplicationContext context;

	@Before
	public void setup() {
		RestAssuredMockMvc.webAppContextSetup(this.context);
	}
}

Explicit 모드를 사용한다면, 일반적인 통합 테스트에서 흔히 볼 수 있듯이, 베이스 클래스를 통해 테스트하는 애플리케이션 전체를 초기화할 수 있다. 그 방법은 다음 예제를 참고해라:

import io.restassured.RestAssured;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
public abstract class BaseTestClass {

	@LocalServerPort
	int port;

	@Before
	public void setup() {
		RestAssured.baseURI = "http://localhost:" + this.port;
	}
}

JAXRSCLIENT 모드를 사용하는 경우, 베이스 클래스에 protected WebTarget webTarget 필드도 필요하다. 현재 JAX-RS API를 테스트하려면 웹 서버를 시작하는 방법밖에 없다.


6.9. Using Different Base Classes for Contracts

명세contract마다 베이스 클래스가 다르다면, 테스트를 자동 생성할 때 어떤 클래스를 상속할지 Spring Cloud Contract 플러그인에 지정할 수 있다. 다음과 같은 두 가지 옵션을 제공한다:

6.9.1. By Convention

컨벤션이 뭐냐면, 예를 들어 src/test/resources/contract/foo/bar/baz/에 명세contract를 저장하고 packageWithBaseClasses 프로퍼티 값을 com.example.base로 설정했다면, Spring Cloud Contract Verifier는 com.example.base 패키지 밑에 BarBazBase 클래스가 있다고 가정한다. 즉, 마지막에 두 depth의 디렉토리가 있다면, 이 두 디렉토리 명에 Base를 붙인 이름의 클래스를 찾는다. 이 규칙은 baseClassForTests보다 우선한다. 다음은 contracts 클로저에 설정을 추가하는 예시다:

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<configuration>
		<packageWithBaseClasses>hello</packageWithBaseClasses>
	</configuration>
</plugin>

6.9.2. By Mapping

직접 정규식을 사용해 명세contract 패키지를 베이스 클래스의 풀네임fully qualified name에 매핑할 수 있다. baseClassMappings에는 목록을 지정해야 하는데, 각각 contractPackageRegexbaseClassFQN에 매핑하는baseClassMapping 객체를 추가하면 된다. 다음 예제를 살펴보자:

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<configuration>
		<baseClassForTests>com.example.FooBase</baseClassForTests>
		<baseClassMappings>
			<baseClassMapping>
				<contractPackageRegex>.*com.*</contractPackageRegex>
				<baseClassFQN>com.example.TestBase</baseClassFQN>
			</baseClassMapping>
		</baseClassMappings>
	</configuration>
</plugin>

다음과 같은 디렉토리에 명세contract가 있다고 가정해보자:

매핑에 실패한 경우를 대비해서 폴백으로 baseClassForTests를 제공할 수 있다. (packageWithBaseClasses를 폴백으로 사용해도 좋다.) 이렇게 하면 src/test/resources/contract/com/ 에 있는 명세contract로 생성한 테스트는 com.example.ComBase를 상속하고, 나머지 테스트는 com.example.FooBase를 상속하게 된다.


6.10. Invoking Generated Tests

Spring Cloud Contract 메이븐 플러그인은 /generated-test-sources/contractVerifier라는 디렉토리에 검증 코드를 생성하고, 이 디렉토리를 testCompile goal에 첨부한다.

Groovy Spock 코드에선 다음과 같은 설정을 사용할 수 있다:

<plugin>
	<groupId>org.codehaus.gmavenplus</groupId>
	<artifactId>gmavenplus-plugin</artifactId>
	<version>1.5</version>
	<executions>
		<execution>
			<goals>
				<goal>testCompile</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<testSources>
			<testSource>
				<directory>${project.basedir}/src/test/groovy</directory>
				<includes>
					<include>**/*.groovy</include>
				</includes>
			</testSource>
			<testSource>
				<directory>${project.build.directory}/generated-test-sources/contractVerifier</directory>
				<includes>
					<include>**/*.groovy</include>
				</includes>
			</testSource>
		</testSources>
	</configuration>
</plugin>

프로듀서provider가 명세contract를 준수하고 있는지 확인하려면 mvn generateTest test를 실행해야 한다.


6.11. Pushing Stubs to SCM

SCMSource Control Management 레포지토리에 명세contract와 스텁stub을 보관하는 경우, 스텁stub을 레포지토리에 푸시하는 과정을 자동화하고 싶을 수 있다. 이땐 pushStubsToScm goal을 추가하면 된다. 그 방법은 다음 예시를 참고해라:

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <!-- Base class mappings etc. -->

        <!-- We want to pick contracts from a Git repository -->
        <contractsRepositoryUrl>git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</contractsRepositoryUrl>

        <!-- We reuse the contract dependency section to set up the path
        to the folder that contains the contract definitions. In our case the
        path will be /groupId/artifactId/version/contracts -->
        <contractDependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>${project.artifactId}</artifactId>
            <version>${project.version}</version>
        </contractDependency>

        <!-- The contracts mode can't be classpath -->
        <contractsMode>REMOTE</contractsMode>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <!-- By default we will not push the stubs back to SCM,
                you have to explicitly add it as a goal -->
                <goal>pushStubsToScm</goal>
            </goals>
        </execution>
    </executions>
</plugin>

SCM Stub Downloader 사용하기 페이지에서는, <configuration><contractsProperties> 맵이나, 시스템 프로퍼티, 환경 변수를 통해 전달할 수 있는 모든 설정 옵션을 확인할 수 있다. 예를 들어, 디폴트 브랜치 대신 checkout할 구체적인 브랜치를 지정할 수 있다.

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <!-- Base class mappings etc. -->

        <!-- We want to pick contracts from a Git repository -->
        <contractsRepositoryUrl>git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</contractsRepositoryUrl>
	<contractsProperties>
            <git.branch>another_branch</git.branch>
        </contractsProperties>

        <!-- We reuse the contract dependency section to set up the path
        to the folder that contains the contract definitions. In our case the
        path will be /groupId/artifactId/version/contracts -->
        <contractDependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>${project.artifactId}</artifactId>
            <version>${project.version}</version>
        </contractDependency>

        <!-- The contracts mode can't be classpath -->
        <contractsMode>REMOTE</contractsMode>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <!-- By default we will not push the stubs back to SCM,
                you have to explicitly add it as a goal -->
                <goal>pushStubsToScm</goal>
            </goals>
        </execution>
    </executions>
</plugin>

6.12. Maven Plugin and STS

다음은 STS를 사용할 때 만날 수 있는 exception이다:

STS Exception

에러 마커를 클릭하면 다음과 같은 내용을 확인할 수 있다:

 plugin:1.1.0.M1:convert:default-convert:process-test-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
 cloud-contract-maven-plugin:1.1.0.M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145) at
 org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331) at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362) at
...
 org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) Caused by: java.lang.NullPointerException at
 org.eclipse.m2e.core.internal.builder.plexusbuildapi.EclipseIncrementalBuildContext.hasDelta(EclipseIncrementalBuildContext.java:53) at
 org.sonatype.plexus.build.incremental.ThreadBuildContext.hasDelta(ThreadBuildContext.java:59) at

이 이슈를 해결하려면 pom.xml에 아래 설정을 추가해야 한다:

<build>
    <pluginManagement>
        <plugins>
            <!--This plugin's configuration is used to store Eclipse m2e settings
                only. It has no influence on the Maven build itself. -->
            <plugin>
                <groupId>org.eclipse.m2e</groupId>
                <artifactId>lifecycle-mapping</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <lifecycleMappingMetadata>
                        <pluginExecutions>
                             <pluginExecution>
                                <pluginExecutionFilter>
                                    <groupId>org.springframework.cloud</groupId>
                                    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
                                    <versionRange>[1.0,)</versionRange>
                                    <goals>
                                        <goal>convert</goal>
                                    </goals>
                                </pluginExecutionFilter>
                                <action>
                                    <execute />
                                </action>
                             </pluginExecution>
                        </pluginExecutions>
                    </lifecycleMappingMetadata>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

6.13. Maven Plugin with Spock Tests

명세contract 테스트를 자동 생성하고 실행하기 위해 Spock 프레임워크를 선택할 수 있으며, Maven과 Gradle 모두 사용할 수 있다. 단, Gradle에선 간단하지만, Maven에서는 테스트 코드를 적절히 컴파일하고 실행하기 위한 몇 가지 추가 설정이 필요하다.

가장 먼저, 프로젝트에 Groovy를 추가하려면 GMavenPlus와 같은 플러그인이 필요하다. GMavenPlus 플러그인에서는 베이스 테스트 클래스를 정의한 경로와 명세contract 테스트를 자동 생성할 경로를 포함한 테스트 소스를 명시해야 한다. 그 방법은 다음 예시를 참고해라:

<plugin>
    <groupId>org.codehaus.gmavenplus</groupId>
    <artifactId>gmavenplus-plugin</artifactId>
    <version>1.13.0</version>
    <executions>
        <execution>
            <goals>
                <goal>addSources</goal>
                <goal>addTestSources</goal>
                <goal>compile</goal>
                <goal>compileTests</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <testSources>
            <testSource>
                <directory>${project.basedir}/src/test/groovy</directory>
                <includes>
                    <include>**/*.groovy</include>
                </includes>
            </testSource>
            <testSource>
                <directory>
                    ${project.basedir}/target/generated-test-sources/contracts/com/example/beer
                </directory>
                <includes>
                    <include>**/*.groovy</include>
                    <include>**/*.gvy</include>
                </includes>
            </testSource>
        </testSources>
    </configuration>

Spock 컨벤션에 따라 테스트 클래스명이 Spec으로 끝나는 경우, 다음과 같이 Maven Surefire 플러그인 설정도 그에 맞게 변경해야 한다:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <detail>true</detail>
        <includes>
            <include>**/*Test.*</include>
            <include>**/*Tests.*</include>
            <include>**/*Spec.*</include>
        </includes>
        <failIfNoTests>true</failIfNoTests>
    </configuration>
</plugin>

Next :
7. “How-to” Guides
스프링 클라우드 컨트랙트 how-to 가이드

전체 목차는 여기에 있습니다.

<< >>

TOP