테스트

외부 api를 테스트하는 방법

이째형 2022. 8. 29. 23:01

- RestTemplate

스프링에서 외부 api를 호출해야 할 상황이 있는 경우, 간단하게 spirng에 내장 된 restTemplate을 이용할 수 있습니다.

@Slf4j
@Transactional
@Service
public class DeliveryService {
    private final DeliveryRepository deliveryRepository;
    private final RestTemplate restTemplate;
    private static String serverUrl;
    private final BalanceHistoryRepository balanceHistoryRepository;
    private final DeliveryRepositorySupport deliveryRepositorySupport;

    @Value("${restApiUrl}")
    public void setServerUrl(String serverUrl) {
        DeliveryService.serverUrl = serverUrl;
    }

    public DeliveryService(DeliveryRepository deliveryRepository, RestTemplateBuilder restTemplateBuilder, BalanceHistoryRepository balanceHistoryRepository, DeliveryRepositorySupport deliveryRepositorySupport) {
        this.deliveryRepository = deliveryRepository;
        this.restTemplate = restTemplateBuilder.build();
        this.balanceHistoryRepository = balanceHistoryRepository;
        this.deliveryRepositorySupport = deliveryRepositorySupport;
    }

    public String deliveryStart(DeliveryCreate dto,Rider rider) {
        Delivery delivery = Delivery.create(rider,dto);
        deliveryRepository.save(delivery);

        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(serverUrl +"/delivery/start");
        DeliveryStartReq request = new DeliveryStartReq(delivery);

        return restTemplate.postForObject(builder.toUriString(),request,String.class);
    }

위 코드는 단순하게 엔티티를 만들어서 저장하고, restTemplate을 이용하여 dto를 외부 api로 post 전송하는 서비스단 코드입니다.

 

※ Spring Framework 5부터는 WebFlux 스택과 함께 Spring은 WebClient 라는 새로운 HTTP 클라이언트를 도입하여 기존의 동기식 API를 제공할 뿐 만 아니라 효율적인 비차단 및 비동기 접근 방식을 지원하여, Spring 5.0 이후 부터는 RestTemplate는 deprecated 되었습니다. (WebClient 사용 지향)

 

위와 같이 외부의 api 연동에 대한 테스트 코드를 작성하려는 경우엔 어떻게 해야할까요?

 

@RestClientTest

https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing

 

RestTemplate을 이용했을 경우,@RestClientTest어노테이션을 이용하여 테스트를 진행 할 수 있습니다.

 

@RestClientTest를 이용할 경우,

  • 외부 API를 MOCKING 할 수 있습니다.
  • MockRestServiceServer라는 임시 서버를 Bean으로 생성해줍니다.

- 서비스 테스트 코드

@RestClientTest(value = DeliveryService.class)
class DeliveryServiceTest {
    @Autowired
    DeliveryService deliveryService;
    @MockBean
    DeliveryRepository deliveryRepository;
    @MockBean
    BalanceHistoryRepository balanceHistoryRepository;
    @MockBean
    DeliveryRepositorySupport deliveryRepositorySupport;
    @Autowired
    private MockRestServiceServer mockServer;

    @Test
    @DisplayName("운행 시작 성공")
    void deliveryStart() {
        //given
        Rider rider = Rider.builder()
                .name("test")
                .driverId("GG1234")
                .build();

        DeliveryCreate req = DeliveryCreate.builder()
                .receiveId("20220928dsd")
                .clientName("맥도날드")
                .requestTime("2022-09-28 14:25:47")
                .appointTime("2022-09-28 14:26:00")
                .build();

        String expectedApiUrl = "http://localhost/delivery/start";
        String expectedJsonResponse = "ok";

        mockServer.expect(requestTo(expectedApiUrl))
                .andExpect(method(HttpMethod.POST))
                .andRespond(withSuccess(expectedJsonResponse, MediaType.APPLICATION_JSON));

        //when
        String result = deliveryService.deliveryStart(req, rider);

        //then
        assertThat(result).isEqualTo("ok");
    }

 

MockRestServiceServer의 expect(requestTo(...)) 메소드를 이용해서 서비스단에서 설정한 url과 테스트 요청 url이 일치하는지 확인할 수 있으며, method()와 andRespond() 메소드를 이용해서 http메소드와 응답값을 검증할 수 있습니다.

( 위 코드의 경우 단순하게 응답 값이 String "ok"일 경우 정상적으로 테스트를 통과할 수 있습니다. )

mockServer.expect(requestTo(expectedApiUrl))
        .andExpect(method(HttpMethod.POST))
        .andRespond(withSuccess(expectedJsonResponse, MediaType.APPLICATION_JSON));

※ 주의

Parameter 1 of constructor in jjfactory.simpleapi.business.delivery.service.DeliveryService required a bean of type 'org.springframework.web.client.RestTemplate' that could not be found.

 

 RestTemplate은 Mocking되지 않는다는 단점이 있습니다. 따라서 서비스단에서 restTemplate이아닌 restTemplateBuilder를 이용해주셔야 위와같은 에러코드를 만나지 않을 수 있습니다!

 

public DeliveryService(DeliveryRepository deliveryRepository, RestTemplateBuilder restTemplateBuilder, BalanceHistoryRepository balanceHistoryRepository, DeliveryRepositorySupport deliveryRepositorySupport) {
        this.deliveryRepository = deliveryRepository;
        this.restTemplate = restTemplateBuilder.build();
        this.balanceHistoryRepository = balanceHistoryRepository;
        this.deliveryRepositorySupport = deliveryRepositorySupport;
    }

 

다음 시간에는 deprecated 된 restTemplate이 아닌, webClient를 이용한 클라이언트 요청과 그 테스트를 하는 방법을 알아보도록 하겠습니다.

 

 

- 참고

https://blog.naver.com/hj_kim97/222295259904

 

[Spring]스프링 RestTemplate

스프링 RestTemplate - RestTemplate란? - RestTemplate의 특징 - RestTemplate 동작 원리 - AP...

blog.naver.com

https://jojoldu.tistory.com/341

 

Spring Boot에서 외부 API 테스트하기

안녕하세요? 이번 시간엔 Spring Boot의 @RestClientTest 예제를 진행해보려고 합니다. 모든 코드는 Github에 있기 때문에 함께 보시면 더 이해하기 쉬우실 것 같습니다. 1. 문제 상황 예를 들어 외부 API를

jojoldu.tistory.com

 

'테스트' 카테고리의 다른 글

테스트 픽스처 (스프링 캠프 2024)  (1) 2024.09.13
@RequestPart 테스트  (1) 2022.10.06
쿼리 dsl 테스트 코드작성  (0) 2022.09.22
@AuthenticationPrincipal 테스트하기  (0) 2022.07.18
@JdbcTest  (0) 2022.06.23