9. 마이크로서비스 테스트 1부

Bonjugi·2022년 8월 27일
0
post-custom-banner

출처 :
마이크로서비스 패턴 (책)

큰 모놀리식 애플리케이션은 테스트하기 아주 어렵다.
테스터블리티 확보는 msa 도입 계기중 하나.
msa 는 특유의 복잡성 때문에 반드시 자동화 필요. (상호작용까지)
9장은 개론을, 10장은 고급 테스트 개념을 다룬다.


여기서 부터는 독후감
9장은 단위테스트 위주이며 mocking 을 활용 하기 때문에 10장이 좀더 기대가 된다.
여기서 재미있던 것은 컨슈머 주도 계약 테스트 (cdc) 였다.
스프링 클라우드 컨트랙트를 활용해서 컨슈머가 주도하여 계약을 생성하는건데, 이부분은 좀 신선 하긴 했으나 쉽게 적용할수 있을지 잘 모르겠다.
특히 컨슈머가 프로듀서 코드베이스를 커밋 해야 한다는점은 일리가 있긴 한데, 컨슈머에게 문법이든, 스펙작성이든 뭔가를 강요해야 하는듯한 느낌을 줄수 있을것 같다.
또한 컨트랙트는 또 누가 관리해야하나.. 물론 백엔드가 하면 되겠지만 백엔드 입장에서도 관리포인트가 계속 늘어난다.
gw 때도 느꼈었지만 모든 컴포넌트와 패턴이 유용한건 맞지만, 모든 msa 컴포넌트가 그렇듯 팀의 구조도 받쳐줘야 유지할수 있다.
그냥 백엔드에서 떼워도 될만한 컴포넌트일수 있으니 어느정도 실리가 있는지 따져보고 차용하도록 하는게 좋겠다.

9.1 msa 테스트 전략

테스트의 목적 : sutd 의 동작을 확인하는것
여기서 system 이란?

  • 테스트해야 할 소프트웨어 엘리먼트를 가리킴.
    - 작은단위 : 클래스 (클래스가 너무 크면 하나의 메소드일수도)
    - 큰 단위 : 전체애플리케이션
    - 중간 단위 : 여러 클래스나 개별 서비스

테스트 스위트?

  • 서로 연관된 테스트를 모아놓은것

자동화 테스트 4단계

  1. 설정
    • SUT와 그 디펜던시로 구성된 픽스처를 초기화 함.
    • 테스트 대상 클래스를 생성, 원하는 동작을 수행할수 있는 상태로
      - (궁금한것) 이건 실행단계의 given 에서도 할수있는것 아닌가?
  2. 실행
  3. 확인
  4. 정리 (teardown)
    • 픽스처를 깨끗이 정리. 설정 단계에서 초기화한 DB 트랜잭션 롤백 등

before이나 teardown에서 실행하는 정리메소드같은건 별도 테스트 클래스에 두자. (중복제거)

mock/stub 을 이용한 테스트

sut 는 대부분 디펜던시를 갖고있다.
OrderController 를 테스트하기위해 service, repository 모두 띄우는것은 느림.

테스트더블 2종류

  • stub : sut 에 값을 반환하는 테스트 더블
  • mock : sut가 정확하게 디펜던시를 호출했는지 확인하는 테스트 더블

모키토 쓰다보면 2개를 딱히 구분하진 않긴 한다.
mock 객체를 만들어줘야 stubing 을 할수 있고 verifing 할수 있기 때문.

테스트 종류

종류는 아주 다양하다.

  • 성능테스트, 사용성테스트 같은 서비스 품질 수준 확인
  • 서비스 동작여부 테스트
    - unit test
    • integration test : 어플리케이션이 인프라,서비스 등과 잘 작동하는지
    • component test : 개별 서비스에 대한 acceptence test
    • end-to-end test : 전체 애플리케이션에 대한 acceptence test
      • integration test 와 차이점?

테스트 사분면: 테스트 분류 기준

  • 비즈니스? 기술?
    - 비즈니스 : 도메인용어를 쓰고
    • 기술 : 구현 용어를 써서 기술
  • 프로그래밍 지원? 애플리케이션 평가?
  • Q1: 프로그래밍/기술 지원 - 단위/통합
  • Q2: 프로그래밍/비즈니스 지원 - 컴포넌트/종단
  • Q3: 애플리케이션/비즈니스 평가 - 사용성/예비
  • Q4: 애플리케이션/기술 평가 - 비기능 인수 테스트

테스트 피라미드: 테스트 역량을 집중

단위테스트

  • 작성하기 쉬움, 빨리끝남

거시적인 종단간 테스트

  • 작성하기 어려움, 느리고 복잡함, 잘깨짐

효용성에 문제가 없는 한도 내에서 가장 범위가 좁은 테스트를 작성하는게 최선.
이 장에서는 주로 서비스 조각을 테스트 하는 전략에 대해서 이야기 한다.
이러면 전체 서비스를 테스트하는 컴포넌트 테스트 개수도 최대한 줄어든다.

  • 소비자 서비스처럼 독립적인건 명백함
  • 다양한 서비스와 엮인 주문 서비비스는 어떻게?

9.1.2 마이크로서비스 테스트

화살표는 모두 의존성방향.

컨슈머 주도 계약 테스트

API gw 에서 주문서비스 GET /orders/{orderId} 를 테스트 한다고 가정시 관계

  • 컨슈머 : API gw
  • 프로바이더 : 주문서비스

컨슈머는 프로바이더가 다음과 같은 일을 하는 endpoint 가 구현되었는지 확인한다.

  • HTTP method, uri, header, body, 등.

컨슈머 계약 테스트는 비즈니스 로직을 빠짐없이 체크하는 테스트가 아니다.
mock controller 테스트 이다.

컨슈머쪽 개발자가 프로바이더 쪽에 테스트 스위트를 추가한다!?
코드 반영은 PR을 요청하는식이라니..
역시나 배포 파이프라인이 컨슈머쪽에 있다.
컨슈머가 기대한 대로 프로바이더 컨트롤러가 잘 작성되었는지를 체크할수 있다.
의도는 알겠는데.. 실제로 이런식으로 운영이 가능할까??

Service Integration Contract Test 라고도 한다.
상호간 작용을, 계약(contract) 이라는 샘플 모음집으로 정의 하는것.

예를들어 rest api 계약은, 요청/응답 샘플을 모아놓은것.
스키마는 유용하지 않다. 어차피 프로바이더에 샘플 요청을 넘겨 호출하기 때문.

서비스 테스트: 스프링 클라우드 컨트랙트

Pact 프레임워크군 중 하나.
그루비 DSL 작성 가능.

  1. 계약 작성. 작성된 계약은 pr 로 주문서비스에 전달
  2. 주문 서비스 팀은 contract test로 주문 서비스를 테스트. 테스트코드는 자동생성된다.
  3. 주문 서비스 팀은 주문 서비스를 테스트한 계약을 메이븐 저장소로 jar 발행
  4. 주문서비스 팀이 발행한 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.2 서비스 단위 테스트 작성

독립 단위 테스트 vs 공동 단위 테스트?

독립 단위 테스트 (어디에도 속하지 않는 비즈니스 로직을 구현한 클래스, 즉 도메인 서비스)

  • 컨트롤러, 서비스, 인/아웃바운드 메시징 게이트웨이

공동 단위 테스트 (사가처럼 여러 서비스에 걸쳐있는경우)

  • 엔티티, 밸류, 사가
public class OrderTest {

  private ResultWithEvents<Order> createResult;
  private Order order;

  @Before
  public void setUp() throws Exception {
    createResult = Order.createOrder(CONSUMER_ID, AJANTA_ID, CHICKEN_VINDALOO
     _LINE_ITEMS);
    order = createResult.result;
  }

  @Test
  public void shouldCalculateTotal() {
     order.getOrderTotal());
  }

  ...

}

Order 는 Money 밸류 객체에 의존한다. Money 밸류 객체도 반드시 함께 테스트 해야 한다. -> 공동 단위 테스트

9.2.5 단위테스트 작성: 컨트롤러

서블릿 mocking 해서 하는 단위 테스트가 예시로 나온다.
인터넷에 많은 예시들이 있으므로 생략

9.2.6 단위테스트 작성: 이벤트/메시지 핸들러

OrderEventConsumer가 각 이벤트를 적절한 핸들러로 라우팅해서 OrderService가 올바르게 호출되었는지 확인한다.
이벤추에이트 트램 목 메시징 프레임워크 를 활용하는 예시여서 생략

post-custom-banner

0개의 댓글