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

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

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


여러 프로그래밍 언어가 공존하는 환경이라면, Artifactory와 Nexus같은 바이너리 저장소를 사용하지 않는 언어도 존재할 거다. Spring Cloud Contract는 2.0.0부터 SCMSource Control Management 레포지토리에 명세contract와 스텁stub을 저장할 수 있다. 현재 지원하는 유일한 SCM은 Git이다.

레포지토리에는 다음과 같은 설정이 있어야 한다 (이곳에서 체크아웃받을 수 있다):

.
└── META-INF
    └── com.example
        └── beer-api-producer-git
            └── 0.0.1-SNAPSHOT
                ├── contracts
                │   └── beer-api-consumer
                │       ├── messaging
                │       │   ├── shouldSendAcceptedVerification.groovy
                │       │   └── shouldSendRejectedVerification.groovy
                │       └── rest
                │           ├── shouldGrantABeerIfOldEnough.groovy
                │           └── shouldRejectABeerIfTooYoung.groovy
                └── mappings
                    └── beer-api-consumer
                        └── rest
                            ├── shouldGrantABeerIfOldEnough.json
                            └── shouldRejectABeerIfTooYoung.json

META-INF 폴더 밑에서는:

마지막으로, 그 밑에는 두 가지 폴더가 있다:

목차

7.6.1. Protocol Convention

레포지토리 URL에 프로토콜을 지정하면, 명세contract를 저장할 타입과 장소를 제어할 수 있다 (바이너리 저장소를 사용할지 SCM 레포지토리를 사용할지). Spring Cloud Contract는 등록돼있는 프로토콜 리졸버들을 순회해서, 명세contract(플러그인을 통해)와 스텁stub(Stub Runner를 통해)을 가져온다.

SCM 기능과 관련해서는, 현재 Git 레포지토리를 지원하고 있다. Git 레포지토리를 사용하려면 레포지토리 URL을 지정하는 프로퍼티 앞에 git://을 붙여줘야 한다. 다음은 몇 가지 예시다:

git://file:///foo/bar
git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git
git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git

7.6.2. Producer

프로듀서producer 경우, 외부 명세contract를 사용할 때와 같은 메커니즘을 이용해 SCMsource Control Management을 사용할 수 있다. Spring Cloud Contract는 git:// 프로토콜로 시작하는 URL을 만나면 SCM 구현체를 사용하도록 라우팅한다.

Maven을 사용 중이라면 pushStubsToScm goal을 수동으로 추가하고, Gradle을 사용 중이라면 pushStubsToScm 태스크를 사용(바인딩)해야 한다. git 레포지토리의 origin에 자동으로 스텁stub을 푸시하지는 않는다.

다음은 Maven, Gradle 빌드 파일에서 관련 설정 부분을 나타낸 예시다:

Maven Gradle
<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>
contracts {
	// We want to pick contracts from a Git repository
	contractDependency {
		stringNotation = "${project.group}:${project.name}:${project.version}"
	}
	/*
	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
	 */
	contractRepository {
		repositoryUrl = "git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git"
	}
	// The mode can't be classpath
	contractsMode = "REMOTE"
	// Base class mappings etc.
}

/*
In this scenario we want to publish stubs to SCM whenever
the `publish` task is invoked
*/
publish.dependsOn("publishStubsToScm")

그래들 publishStubsToScm 태스크는 여기서 좀 더 커스텀할 수 있다. 다음은 로컬 git 레포지토리에 있는 명세contract를 사용하도록 태스크를 커스텀하는 예시다:

gradle

publishStubsToScm {
	// We want to modify the default set up of the plugin when publish stubs to scm is called
	// We want to pick contracts from a Git repository
	contractDependency {
		stringNotation = "${project.group}:${project.name}:${project.version}"
	}
	/*
	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
	 */
	contractRepository {
		repositoryUrl = "git://file://${new File(project.rootDir, "../target")}/contract_empty_git/"
	}
	// We set the contracts mode to `LOCAL`
	contractsMode = "LOCAL"
	}

이렇게 세팅해주면:

7.6.3. Producer with Contracts Stored Locally

스텁stub과 명세contract를 SCM에 저장하는 방식이 하나 더 있는데, 명세contract는 프로듀서producer 코드와 함께 로컬에 저장하고, 프로듀서 코드에서 명세contract와 스텁stub만 따로 SCM에 푸시하는 방식이다. 다음은 이를 위한 Maven, Gradle 설정 예시다:

Maven Gradle
<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <!-- In the default configuration, we want to use the contracts stored locally -->
    <configuration>
        <baseClassMappings>
            <baseClassMapping>
                <contractPackageRegex>.*messaging.*</contractPackageRegex>
                <baseClassFQN>com.example.BeerMessagingBase</baseClassFQN>
            </baseClassMapping>
            <baseClassMapping>
                <contractPackageRegex>.*rest.*</contractPackageRegex>
                <baseClassFQN>com.example.BeerRestBase</baseClassFQN>
            </baseClassMapping>
        </baseClassMappings>
        <basePackageForTests>com.example</basePackageForTests>
    </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>
            <configuration>
                <!-- We want to pick contracts from a Git repository -->
                <contractsRepositoryUrl>git://file://${env.ROOT}/target/contract_empty_git/
                </contractsRepositoryUrl>
                <!-- Example of URL via git protocol -->
                <!--<contractsRepositoryUrl>git://git@github.com:spring-cloud-samples/spring-cloud-contract-samples.git</contractsRepositoryUrl>-->
                <!-- Example of URL via http protocol -->
                <!--<contractsRepositoryUrl>git://https://github.com/spring-cloud-samples/spring-cloud-contract-samples.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 mode can't be classpath -->
                <contractsMode>LOCAL</contractsMode>
            </configuration>
        </execution>
    </executions>
</plugin>
contracts {
    contractsDslDir = file("src/test/resources/contracts")
    testFramework = "JUNIT5"
        // Base package for generated tests
    basePackageForTests = "com.example"
    baseClassMappings {
        baseClassMapping(".*messaging.*", "com.example.BeerMessagingBase")
        baseClassMapping(".*rest.*", "com.example.BeerRestBase")
    }

    /*
    In this scenario we want to publish stubs to SCM whenever
    the `publish` task is executed
    */
    publishStubsToScm {

        // We want to pick contracts from a Git repository
        contractDependency {
            stringNotation = "${project.group}:${project.name}:${project.version}"
        }

        contractRepository {
            /*
            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
             */
            repositoryUrl = "git://file://${new File(project.rootDir, "../target")}/contract_empty_git/"
        }
    }
}

이렇게 세팅해주면:

7.6.4. Keeping Contracts with the Producer and Stubs in an External Repository

명세contract는 프로듀서producer 레포지토리에 보관하고, 스텁stub은 외부 git 레포지토리에 보관하는 방법도 있다. 이 방식은 기본적인 컨슈머consumer-프로듀서producer 플로우를 따르지만, 아티팩트 레포지토리에 스텁stub을 저장하기 어려울 때 가장 유용하다.

이땐 평소처럼 프로듀서producer를 세팅한 다음, pushStubsToScm goal을 추가하고 contractsRepositoryUrl에 스텁stub을 보관할 레포지토리를 설정하면 된다.

7.6.5. Consumer

컨슈머consumer 측에서는 @AutoConfigureStubRunner 어노테이션이나 JUnit 4 rule, JUnit 5 extension, 프로퍼티를 통해 repositoryRoot 파라미터를 전달할 때, SCM 레포지토리 URL 앞에 git:// 프로토콜을 붙이면 된다. 다음 예시를 참고해라:

@AutoConfigureStubRunner(
    stubsMode="REMOTE",
    repositoryRoot="git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git",
    ids="com.example:bookstore:0.0.1.RELEASE"
)

이렇게 세팅해주면:


Next :
7.7. 자동 생성된 테스트 코드에서 클라이언트가 보내는 요청/응답은 어떻게 디버깅하나요?
자동 생성된 테스트 코드에서 클라이언트가 보내는 요청/응답 디버깅하기

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

<< >>

TOP