스프링

[스프링] spring feign client wiremock test

ImNM 2023. 3. 7. 18:32

 

두둥 서비스에서 api client로 feign을 사용중이다.

매우편하게 인터페이스로 선언만 해놓으면, 응답받는거와 비슷한 형식으로 사용가능하다.

또한 인터페이스 이므로 테스트 과정에서 mocking 해야할때도 편하게 진행할수있다.

 

토스페이먼츠에는 발생했던 매출에서 수수료를 뺀 금액 즉 정산 받을 금액을 조회할려면,

 

코어 API | 토스페이먼츠 개발자센터

토스페이먼츠 API 엔드포인트(Endpoint)와 객체 정보, 파라미터, 요청 및 응답 예제를 살펴보세요.

docs.tosspayments.com

정산 조회 작업을 거쳐서 발생 주문 건에 대해서 PG 수수료를 계산해야한다.

 

이전까진 테스트키로 개발을 하다가, 실제 결제가 이루어지기 전까진 정산데이타가 넘어오지 않아서

응답 dto로 알맞게 파싱되는지, 테스트를 해보고 싶었다.

 

파싱이 제대로 되는지,

테스트를 진행하기 위해서는 정말 요청을 보낼수 있는 환경을 구성해서

요청을 보낸뒤에 그에 맞는 응답을 내려주는 형식으로 구성을 해야한다.

 

그방법을 공유하고자 한다.


목차

1. wiremock

2. 적용하기

  2.1. feign client 

  2.2. 테스트 코드 작성하기


1. wiremock

wiremock 은 테스트 목적으로 사용할 수 있는 웹 서버이다. 즉 테스트 환경에서 요청이 들어오면 정해진 응답을 반환 할 수 있다.

wiremock 자체로도 서버를 껏다 킬 수 있지만 스프링과도 연동이 가능하다.

 

10. Spring Cloud Contract WireMock

Modules giving you the possibility to use WireMock with different servers by using the "ambient" server embedded in a Spring Boot application. Check out the samples for more details. If you have a Spring Boot application that uses Tomcat as an embedded ser

cloud.spring.io

testImplementation "org.springframework.cloud:spring-cloud-contract-wiremock:3.1.5"

위 모듈을 추가하게 되면 스프링과 쉽게 연동할 수 있다. ( 공식문서에 있는 내용 )

우린 standalone 모드 대신에 테스트 과정에 포함시킬거다.

[
  {
    "mId": "tosspayments",
    "paymentKey": "5zJ4xY7m0kODnyRpQWGrN2xqGlNvLrKwv1M9ENjbeoPaZdL6",
    "transactionKey": "8B4F646A829571D870A3011A4E13D640",
    "orderId": "a4CWyWY5m89PNh7xJwhk1",
    "currency": "KRW",
    "method": "카드",
    "amount": 34000
  }
]

간단하게 json 파일을 위와 같이 만들어두면,

Path file = ResourceUtils.getFile("classpath:payload/settlement-response.json").toPath();
// 응답예시 생성하기
.withBody(Files.readAllBytes(file))));

테스트 코드 작성시에 미리 만들어둔 json 응답을 줄 수 있다.


2. 적용하기


2.1. feign client

@FeignClient(
        name = "SettlementClient",
        // url 자체를 환경변수로 세팅한다.
        url = "${feign.toss.url}",
        configuration = {TransactionGetConfig.class})
public interface SettlementClient {
    @GetMapping("/v1/settlements")
    List<SettlementResponse> execute(
            @RequestParam(value = "startDate") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
                    LocalDate startDate,
            @RequestParam(value = "endDate") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
                    LocalDate endDate,
            @RequestParam(value = "dateType") String dateType,
            @RequestParam(value = "page") int page,
            @RequestParam(value = "size") int size);
}
// application-infrastructure.yml
feign:
  toss:
    url : https://api.tosspayments.com

일반적인 요청인데 중요한 부분은 url 자체를 환경변수로 넣어야한다는 점이다.

실제 요청 주소를 default 로 세팅 해놓고 테스트를 돌릴 때 @TestPropertySource 로 환경변수를 localhost로 지정줘서

요청을 보낼 것이다.

 

여담이지만 @TestPropertySource 는 엄청 유용하게 쓸데가 많은것 같다.

 

[스프링] Spring disable Aop in test

오랜만에... 글을 씁니다.! 디프만 12기 끝나고 ( 13기 운영진도 할 예정입니다. ㅎㅎ ) 고스락 티켓예매 세번째 프로젝트로 두둥이라는 프로젝트를 시작하게 되었다. 기존엔 고스락만을 위한 예매

devnm.tistory.com

내가 쓴글인 spring disable aop in test 도

테스트 돌 때 어느 한 aop 를 끄고싶을 때도 설정할 수 있다.!

위글에서는 분산락을 aop 통해서 적용하고 있었는데,

분산락 지정을 안했을때의 실패테스트를 하고 싶을 때, 간단하게 환경변수로 분산락 적용을 없앨 수 있다.

유용하니 한번 둘러보길 바란다 ㅎㅎ.

 

이 외엔 일반적인 feign client 모습과 동일하다.


2.2. 테스트 코드 작성하기

@SpringBootTest(classes = InfraIntegrateTestConfig.class)
@AutoConfigureWireMock(port = 0)
@ActiveProfiles(resolver = InfraIntegrateProfileResolver.class)
@TestPropertySource(
        properties = {
            "feign.toss.url=http://localhost:${wiremock.server.port}",
            // 타임리프때문에 테스트 깨져서 넣음
            "spring.thymeleaf.enabled=false"
        })
public class TossSettlementClientTest {

설정부분에서 제일 중요한부분은 

@AutoConfigureWireMock(port = 0) 로설정해서 randomport 상에서 실행되게끔 하는것이고,

feign 클라이언트가 요청 보낼 주소를 localhost 에 어느 random port 인지는

wiremock.server.port 환경변수로 불러올 수 있다. 

 

이렇게 요청보낼 주소를 정할 수 있다.

 

@Configuration
@ComponentScan(basePackageClasses = {DuDoongInfraApplication.class, DuDoongCommonApplication.class})
public class InfraIntegrateTestConfig {}

public class InfraIntegrateProfileResolver implements ActiveProfilesResolver {

    @Override
    public String[] resolve(Class<?> testClass) {
        // some code to find out your active profiles
        return new String[] {"common", "infrastructure"};
    }
}

InfraIntegrateTestConfig , InfraIntegrateProfileResolver는 두둥 프로젝트가 멀티모듈 구조이고

인프라 모듈이 커먼 모듈에 의존성을 가지고 있기 때문에

스프링 부트 테스트를 통한 통합테스트를 진행할 경우 , 스프링 부트 빈 구성을 위해

빈 스캔 범위를 지정하고, 필요한 profile을 편하게 설정하기 위해서 만든 편의 클래스이다.

 

각 모듈 ( 최종 어플리케이션 모듈이 아닌 의존성이있는 모듈등인 경우 )

application-{모듈이름}.yml 형태로 환경변수들을 세팅해 줄 수 있고,

profile에 지정을 해줘야 해당 모듈의 환경변수들을 불러올 수 있다.

 

멀티모듈구조가 아니라면 굳이 설정해 줄 필요가 없다.

 

@Autowired private SettlementClient settlementClient;

@Test
public void 정산요청_올바르게_파싱되어야한다() throws IOException {
    // 만들어둔 json 파일을 불러온다.
    Path file = ResourceUtils.getFile("classpath:payload/settlement-response.json").toPath();
	// import static com.github.tomakehurst.wiremock.client.WireMock.*
    stubFor(
    		// localhost:${wiremock.server.port}/v1/settlements 요청은 willReturn을 한다.
            get(urlPathEqualTo("/v1/settlements"))
                    .willReturn(
                            aResponse()
                                    .withStatus(HttpStatus.OK.value())
                                    .withHeader(
                                            "Content-Type", MediaType.APPLICATION_JSON_VALUE)
                                    // 바디 지정
                                    .withBody(Files.readAllBytes(file))));
    LocalDate now = LocalDate.now();
    // 실제 요청이 List<SettlementResponse>에 담겨서온다 
    List<SettlementResponse> test = settlementClient.execute(now, now, "test", 1, 10);
	
    SettlementResponse settlementResponse = test.get(0);
    // 파싱이 제대로 되었는지 확인.. 다 확인은 안하고 디버거로 적당히 했다.!
    assertEquals(settlementResponse.getFees().size(), 2);
}

위처럼 코드작성을 하게 되면

실제로 응답이 잘 파싱되는지 확인 할 수 있다.

Enum 값이나 iso 형식으로 넘어오는 날짜 데이타들이 잘 파싱되는것을 볼 수 있다.

 

이렇게 wiremock 을 활용해서 테스트 코드간에 응답을 미리 지정해서 

요청을 보낸뒤에 파싱이 잘되는지 확인해 보았다.


 

GitHub - Gosrock/DuDoong-Backend: 모두를 위한 새로운 공연 라이프, 두둥!

모두를 위한 새로운 공연 라이프, 두둥! Contribute to Gosrock/DuDoong-Backend development by creating an account on GitHub.

github.com

소스 코드는 레포지토리에서 확인 가능하다.

파싱이 잘되는지 볼려면... 매번 요청을 보내고 받았어야 했는데.

이렇게 테스트 작성하는 방법을 파악하고 나니

불편함이 많이 줄었다!