- 도커
- remix icon
- with jdk
- openapispec
- 리믹스아이콘
- 전략패턴
- OneToMany
- fontawesome
- arc browser
- Spring
- Openjdk
- Observer Pattern
- 라즈베리파이 클러스터
- java_to_kotlin
- kotlin
- 무료 아이콘 폰트
- EntityGraph
- restcontroller
- 폰트어썸
- QueryDSL
- 옵저버패턴
- 라즈베리파이
- java
- spring cloud contract
- 디자인패턴
- Docker
- restdocs
- oraclejdk
- springboot
- Spring Cloud
- Today
- Total
< Dev-Kidult />
`Spring cloud contract` 를 배워보자 본문
예제(코드)는 깃허브에 있습니다.
1. Spring cloud contract 이전은 어떻게 테스트를 했을까
- 모든 마이크로 서비스를 올리고 엔드 투 엔드 테스트를 한다.
- 다른 마이크로 서비스 목(mock)을 만들어서 유닛 및 통합 테스트를 한다.
2. 모든 마이크로 서비스를 올리고 엔드 투 엔드 테스트를 했을 때
장점:
- 서비스를 시뮬레이터 할 수 있음.
- 서비스 간 실제 통신을 테스트.
단점:
- 테스트를 하기 위해 모든 마이크로 혹은 연관된 서비스들을 배치해야 함.
- 테스트를 하는 동안 다른 마이크로 서비스는 잠겨 있음. (그동안 아무도 테스트를 하지 못함)
- 테스트를 하기위한 시간이 오래 걸림
- 피드백 과정이 오래 걸림
- 디버깅을 하기가 매우 어려움
3. 다른 마이크로 서비스 목(mock)을 만들어서 유닛 및 통합 테스트를 했을 때
장점:
- 매우 빠른 피드백
- 인프라 요구사항이 없음
단점:
- 목을 만드는 과정이 불안정함
- 목이 불안정함으로써 테스트는 통과했지만 실제 프로덕트 환경에서는 작동하지 않을 수 있음
앞에 언급한 단점들을 보완하기 위해 spring cloud contract가 생성되었다고 공식문서는 말하고 있습니다.
다른 서비스에 api를 제공해주는 producer들은 스텁을 생성하게 되는데 그 과정에서 테스트되어 만들어졌기 때문에 목과는 달리 불안정함이 없음을 알 수 있습니다.
또한 해당 api를 소비하는 consumer들은 소비할 api의 서비스를 구동하지 않아도 해당 스텁을 통해 테스트를 할 수 있기 때문에 빠르며, 정확하고 가볍게 테스트할 수 있습니다.
4. contract란
As consumers of services, we need to define what exactly we want to achieve. We need to formulate our expectations. That is why we write contracts. In other words, a contract is an agreement on how the API or message communication should look.
공식 문서에 따르면 위와 같이 말하고 있습니다.
contract는 groovy yaml(yml) kotlin으로 쓸 수 있으며
/foo라고 요청을 하면 bar라고 응답하는 api 있다고 가정해보겠습니다.
Contract.make {
description "/foo 라고 콜하면 bar를 줄꺼야"
request {
method GET()
url("/foo")
}
response {
body("bar")
status 200
}
}
grooby는 위와 같이 작성할 수 있으며, 나머지 yaml 및 kotlin은 공식 문서 및 공식 샘플 깃허브를 가면 볼 수 있습니다.
5. 예제
모든 예제는 spring kotlin gradle 기반입니다.
Producer
먼저 생산자쪽에서는 이와 같이 dependencie 및 plugin을 추가해 줍니다.
buildscript {
...
val verifierVersion: String by extra
dependencies {
classpath("org.springframework.cloud:spring-cloud-contract-spec-kotlin:$verifierVersion")
}
}
plugins {
...
id("org.springframework.cloud.contract") version "2.2.4.RELEASE"
id("maven-publish")
}
dependencies {
...
testImplementation("org.springframework.cloud:spring-cloud-starter-contract-verifier")
testImplementation("org.springframework.cloud:spring-cloud-contract-spec-kotlin")
}
contracts {
baseClassForTests.set("yh.study.producer.ProducerBase") // 1
}
1. contracts 플러그인에는 많은 옵션이 있지만 여기서는 contract의 테스트 기본이 되는 베이스 클래스를 하나 만들고 contract 작성 기반 테스트 코드들이 자동으로 만들어지는 걸 선택했습니다.
그리고 서비스하고 있는 API들을 위 contract처럼 하나하나 만들어주고 빌드할 경우 contract기반으로 자동으로 테스트 코드들이 생성됩니다.
그리고 consumer에게 제공하기 위해서 maven-pulish 플러그인을 쓰게 되는데 이 예제에서는 로컬 메이븐에 저장 및 이용을 하게 할 겁니다.
프로젝트 루트에 가셔서 해당 명령어를 치게 되면 로컬 메이븐 레파지토리에 스텁 파일이 생성됩니다.
./gradlew publishToMavenLocal
Consumer
소비자 쪽은 다음과 같은 dependencie 및 plugin을 추가해 줍니다.
dependencies {
...
testImplementation("org.springframework.cloud:spring-cloud-starter-contract-stub-runner")
testImplementation("org.springframework.cloud:spring-cloud-contract-wiremock")
}
테스트를 위한 stub-runner와 contract-wiremock을 추가해 줍니다.
그리고 Producer에서 만든 스텁을 로컬메이븐에서 다음과 같이 가져와줍니다.
그리고 테스트클래스 위에 어노테이션을 아래와 같이 채워주시면 됩니다.
...
@AutoConfigureStubRunner(
stubsMode = StubRunnerProperties.StubsMode.LOCAL,
ids = ["{project.group}:{project.artifact}:+:stubs:{api.port}"] // 1
)
...
1.
- {project.group} 에는 해당 프로젝트 그룹명을
- {project.artifact} 에는 해당 프로젝트 아티팩트를
- {api.port} 에는 해당 API 포트 넘버를
각각 프로젝트 설정에 맞게 내용을 채워 주시면 됩니다.
그리고 스텁의 API를 호출하는 컨트롤러 혹은 서비스 테스트를 만들어주면 완성입니다.
'개발 > Back-end' 카테고리의 다른 글
Springboot - QueryBinder (0) | 2022.12.28 |
---|---|
Spring boot JPA Specification + Spring filter 파라미터로 쉽게 조회하기 (0) | 2022.04.21 |
JPA OneToMany EAGER 문제 및 해결방안 (0) | 2020.07.30 |
디자인 패턴 - 옵저버패턴(Observer pattern) with jdk (0) | 2019.07.11 |
디자인 패턴 - 전략패턴(Strategy pattern) (0) | 2019.06.29 |