9장 마이크로서비스 테스트 1부 안겹치게2
목차
1
2
3
4
5
6
7
8
9
10
11
12
13
9장 마이크로서비스 테스트 1부
9.1 마이크로서비스 아키텍처 테스트 전략
__9.1.1 테스트 개요
__9.1.2 마이크로서비스 테스트
__9.1.3 배포 파이프라인
9.2 서비스 단위 테스트 작성
__9.2.1 단위 테스트 작성: 엔터티
__9.2.2 단위 테스트 작성: 밸류 객체
__9.2.3 단위 테스트 작성: 사가
__9.2.4 단위 테스트 작성: 도메인 서비스
__9.2.5 단위 테스트 작성: 컨트롤러
__9.2.6 단위 테스트 작성: 이벤트/메시지 핸들러
9.3 마치며
정리 전략?
- 전부 정리는 NO
- 핵심중에서 꼭 적고 가야겠다 싶은 것만!
- 나의 생각을 섞어서 적을것..!
- 떠오르는 것 먼저 간단하게..!
내용
9장 마이크로서비스 테스트 1부
9.1 마이크로서비스 아키텍처 테스트 전략
__9.1.1 테스트 개요
자동화 테스트 작성
- 익히 알던것.
목/스텁을 이용한 테스트
- 목과 스텁의 차이? Stub 인스턴스화하여 구현한 가짜 객체(Dummy, 기능 구현이 없음)을 이용해 실제로 동작하는 것처럼 보이게 만드는 객체입니다. 해당 인터페이스나 클래스를 최소한으로 구현합니다. 테스트에서 호출된 요청에 대해 미리 준비해둔답변을 응답합니다. 테스트시에 프로그래밍된 것 외에는 응답하지 않습니다. 협력 객체의 특정 부분이 테스트가 어려운 경우, stub을 사용하여 수월하게 테스트할 수 있습니다. Stub’s Lifecycle Setup, 테스트 준비 Exercise, 테스트 Verify state, 상태 검증 Teardown, 리소스 정리 Mock 호출에 대한 기대를 명세하고, 내용에 따라 동작하도록 프로그래밍 된 객체입니다. 테스트 작성을 위한 환경 구축이 어려울 때, 테스트하고자 하는 코드와 엮인 객ㅊ들을 대신하기 위해 만들어진 객체입니다. 행위 검증을 진행합니다. Mock’s Lifecycle Setup data, 데이터 준비 Setup expectations, 예상되는 결과 준비 Exercise, 테스트 Verify expectations, 예상 검증 Verify state, 상태 검증 Teardown, 리소스 정리 Stub과 Mock의 차이 stub을 포함한 다른 대역들은 상태 검증(state verification) 을 사용하고 Mock 오브젝트는 행위 검증(behavior verification) 을 사용합니다.
상태 검증이란 메소드가 수행된 후, 객체의 상태를 확인하여 올바르게 동작했는지를 확인하는 검증법입니다. 행위 검증이란 메소드의 리턴 값으로 판단할 수 없는 경우, 특정 동작을 수행하는지 확인하는 검증법입니다. 검증의 대상이 다르다는 것이 중요한 체크 요소입니다.
https://azderica.github.io/00-test-mock-and-stub/
테스트 종류.
- 단위 테스트 : 서비스의 작은 부분을 테스트(클래스)
- 통합 테스트 : 어플리케이션 서비스의 인프라 및 외부서비스와의 연동 테스트
- 컴포넌트 테스트 : 개별서비스들에 대한 인수테스트(Acceptance Test)
- 종단 간 테스트(end-to-end) : 전체 어플리케이션에 대한 인수테스트
테스트 사분면
테스트 피라미드
- 단위테스트는 많이, 종단간 테스트는 적게.
__9.1.2 마이크로서비스 테스트
컨슈머 주도 계약 테스트
- 서비스가 클라이언트의 기대에 부합하는지 확인합니다.ㄴ
- API gw 에서 주문서비스 GET /orders/{orderId} 를 테스트 한다고 가정시 관계
- 컨슈머 : API gw
- 프로바이더 : 주문서비스
- 컨슈머는 프로바이더가 다음과 같은 일을 하는 endpoint 가 구현되었는지 확인한다.
- HTTP method, uri, header, body, 등.
- 컨슈머 계약 테스트는 비즈니스 로직을 빠짐없이 체크하는 테스트가 아니다.
- mock controller 테스트 이다.
- 클라이언트와 서비스가 통신 가능한지 확인한다.
서비스 테스트: 스프링 클라우드 컨트랙트
- 계약 작성. 작성된 계약은 pr 로 주문서비스에 전달
- 주문 서비스 팀은 contract test로 주문 서비스를 테스트. 테스트코드는 자동생성된다.
- 주문 서비스 팀은 주문 서비스를 테스트한 계약을 메이븐 저장소로 jar 발행
- 주문서비스 팀이 발행한 jar 를 내려받아, API 게이트웨이 테스트를 작성한다.
- 컨슈머 쪽에서 효용성
모키토로 스텁해서 주문 서비스 동작을 시뮬레이션 하는 용도로 사용 API 가 실제로 발행이 안되어도 개발이 가능 프로바이더 쪽에서 효용성
code generated 된 테스트 클래스 이용하여, 실제로 프로바이더가 계약에 맞게 응답을 반환하는지 테스트 가능 org.springframework.cloud.contract.spec.Contract.make { request { method ‘GET’ url ‘/orders/1223232’ } response { status 200 headers { header(‘Content-Type’: ‘application/json;charset=UTF-8’) } body(“{ … }”) } } API 게이트웨이가 주문 서비스를 어떻게 호출하는지 기술한 계약
컨슈머 계약 테스트: 메시징 API
스프링 클라우드 컨트랙트는 메시징 기반도 테스트 가능.
- 프로바이더쪽
- 이벤트 발생시키도록 만들고 그것이 계약과 일치하는지 확인.
- 컨슈머쪽
- 이 이벤트를 컨슈머가 처리할수있는지 확인. (스텁 구독기)
__9.1.3 배포 파이프라인
- 배포 파이프라인은 Jenkins같은 CI 툴로 배포 파이프라인을 구성한다.
- 배포 프로세스는 조직마다 상이할 수 있지만, 본 책에서는 아래와 같이 구성했다.
- 커밋 테스트 -> 통합 테스트 -> 컴포넌트 테스트 -> 배포
9.2 서비스 단위 테스트 작성
- 독립 단위 테스트 (어디에도 속하지 않는 비즈니스 로직을 구현한 클래스, 즉 도메인 서비스) : 클래스 디펜던시를 목 객체로 나타내고 클래스를 따로 테스트.
- 컨트롤러, 서비스, 인/아웃바운드 메시징 게이트웨이
- 공동 단위 테스트 (사가처럼 여러 서비스에 걸쳐있는경우) : 클래스와 디펜던시를 테스트.
- 엔티티, 밸류, 사가
__9.2.1 단위 테스트 작성: 엔터티
- 공동 단위테스트 대상.
- Order 라는 엔티티 객체의 메서드 getOrderTotal이 기대한 값을 반환하는지에 대한 테스트 였음.
__9.2.2 단위 테스트 작성: 밸류 객체
- 공동 단위 테스트 대상
- Money라는 벨류 객체의 multiply가 기대값을 반환하는지 확인.
__9.2.3 단위 테스트 작성: 사가
- 정상 테스트, 실패 테스트에 대한 시나리오 테스트 필요.
- 단위테스트를 위해 DB, 메시지브로커와 상호작용하는 클래스는 모킹한 테스트를 작성하는 것이 좋다.
- 사가 테스트 프레임워크를 이용할 수 있음.
- 하부에서 아까 말한 것들을 목으로 대체한 사가 프레임워크를 구성함.
__9.2.4 단위 테스트 작성: 도메인 서비스
- Orderservice : 대표적인 도메인 서비스
- 이것도 리포지토리ㅡ 메시징은 모킹하는게 좋음.
- Mockito를 활용.
- 코드 참고하면 verify를 활용하여 해당 의존성을 의도한 인자를 이용하여 호출했는지 확인하기도함.
1
verify(oR).save(same(order));
__9.2.5 단위 테스트 작성: 컨트롤러
- 이것도 서비스, 레포지토리단 모킹.
- 목mvc 테스트프레임워크 활용 가능.
- 익히 비슷하게 해봄.
- 컨트롤러를 mockMvc로 호출해봐서, 의도한 코드대로 반환하는지 확인.
- StandaloneMockMvcBuilder
__9.2.6 단위 테스트 작성: 이벤트/메시지 핸들러
- 이것도 다른 테스트와 매우 유사하다.
- 결국 핵심 클래스(OrderEventConsumer)이외의 것은 모킹.
- 단 이테스는 이벤추에이트 트램 목 메시징 프레임워크를 이용.
- 각 테스트는 도메인 이벤트를 발행한 후 OrderEventConsumer가 서비스 목을 올바르게 호출하는 지 확인합니다.
- 코드도 말한대로 임.
- 구성하고
- 이벤트 발행했을때
- eventConsumer가 적절한 메서드를 호출했는지 verify로 체크.
9.3 마치며
- 스텁은 SUT에 값을 반환하는 용도로, 목은 SUT가 정확ㄱ하게 디펜던시를 호출하는지 확인하는 용도로 사용.
- 나머지는 패스.
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package deliveryservice.messaging;
org.springframework.cloud.contract.spec.Contract.make {
label 'orderCreatedForDeliveryService'
input {
triggeredBy('orderCreatedEvent()')
}
outputMessage {
sentTo('net.chrisrichardson.ftgo.orderservice.domain.Order')
body('''{"orderDetails":{"lineItems":[{"quantity":5,"menuItemId":"1","name":"Chicken Vindaloo","price":"12.34","total":"61.70"}],"orderTotal":"61.70","restaurantId":1, "consumerId":1511300065921}, "deliveryAddress":{ "street1" : "9 Amazing View", "city" : "Oakland", "state" : "CA", "zip" : "94612", }, "restaurantName" : "Ajanta"}''')
headers {
header('event-aggregate-type', 'net.chrisrichardson.ftgo.orderservice.domain.Order')
header('event-type', 'net.chrisrichardson.ftgo.orderservice.api.events.OrderCreatedEvent')
header('event-aggregate-id', '99') // Matches OrderDetailsMother.ORDER_ID
}
}
}
참고자료
https://velog.io/@bonjugi/9.-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%85%8C%EC%8A%A4%ED%8A%B8-1%EB%B6%80
https://medium.com/byungkyu-ju/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4%ED%8C%A8%ED%84%B4-9-9%EC%9E%A5-a4fce4ad535b

