[JAVA] MockWebServer 빠르게 사용하기

YJ KIM·2023년 12월 14일
0

이번 게시물은 MockWebServer의 동작과정이나 여러 내부 코드들을 통해 알아보는 것이 아닌 빠르게 테스트에 사용한 과정을 정리한 글이다.

동작은 시간이 되면 확인해보고 싶다. (디버깅을 했을 때에도 과정이 생략되고 갑자기 모킹한 값이 도출되어서 동작과정에 대해 감을 잡지 못하고 있음)

MockWebServer란?

외부 API를 이용하는 서비스를 개발할 때 테스트하기가 매우 까다롭다. 외부 API를 그대로 사용해서 테스트할 수도 있지만 이러면 예외 처리가 매우 종속적이고 사실 외부 API에서 뭔 값을 전달할지 개발자는 모르기 때문이다.

이를 위해 MockWebServer를 사용하여 외부 API에 보내는 요청을 실제로 외부 API가 아닌 MockWebServer로 전달하여 응답을 받도록 한다.

의존성 주입

나는 gradle을 사용하기 때문에 gradle에 의존성을 명시하였다.

testImplementation 'com.squareup.okhttp3:mockwebserver'

버전이 맞는 okhttp3 라이브러리를 추가해야 된다는 의견도 있었지만 위와 같이 의존성을 명시해도 사용 가능하다.

초기 설정

위에서 언급한 것처럼 MockWebServer라는 웹 서버를 생성하기 위해서는 초기 설정이 필요하다. 근데 엄청 간단함

mockWebServer = new MockWebServer();
mockWebServer.start();

생성자를 통해 MockWebServer 객체를 생성하고
start 메소드를 실행시키면 MockWebServer가 구동된다.

  public void start() throws IOException {
    start(0);
  }

  /**
   * Starts the server on the loopback interface for the given port.
   *
   * @param port the port to listen to, or 0 for any available port. Automated tests should always
   * use port 0 to avoid flakiness when a specific port is unavailable.
   */
  public void start(int port) throws IOException {
    start(InetAddress.getByName("localhost"), port);
  }
  
    public void start(InetAddress inetAddress, int port) throws IOException {
    start(new InetSocketAddress(inetAddress, port));
  }

궁금해서 라이브러리 코드 살펴봤는데 그냥 진짜 localhost에 port 열어서 서버 시작하는 거였음

사용 방법

이제 MockWebServer를 구동했으니 실질적으로 모킹하는 법을 알아야 한다.
근데 이것도 간단함

mockWebServer.enqueue(new MockResponse().setBody(데이터));

위와 같이 enqueue 메소드를 통하여 반환할 Response를 넣어주면 된다.

라이브러리에서 내부적으로 정의한 함수들이 queue에 반환할 MockResponse를 넣으면 순차적으로 응답 값으로 반환해준다.

추가적으로 헤더나 여러 설정이 다양한데 이러한 부분은 더 알아보면 좋을 것 같다.
사용할 때는 간단하게 넣어도 다 모킹 됨.

테스트 후 처리

구동한 서버를 다운해야 한다.

    @AfterAll
    static void shutDown() throws IOException {
        mockWebServer.shutdown();
    }

나는 @AfterAll 어노테이션을 통해 테스트가 다 끝나면 서버를 다운하는 형식으로 구현했다.

주의사항

MockWebServer가 실제로 localhost에 port를 열어 작은 웹 서버를 구동하는 것이기 때문에, 서비스에서 해당 url로 요청을 보내야 한다.

실제 api 주소로 요청을 보내면 모킹 천만번을 해도 소용이 없다.

String baseUrl = String.format("http://localhost:%s", mockWebServer.getPort());

위와 같은 baseUrl로 요청을 보내야 한다.

나는 서비스에서 내부에 baseUrl을 멤버 변수로 갖고 있는 형태였기 때문에 서비스를 변경할 수 밖에 없었다.

멤버 변수로 String baseUrl = "원래 API baseUrl"; 과 같은 형태에서
생성자에서 baseUrl을 파라미터로 집어넣는 방식으로 변경하였다.


테스트 코드를 작성하며 느끼는 거지만 테스트를 할 때 원래 서비스 코드를 바꾼다면 그 코드의 구조가 좋지 않다는 방증이라고 생각하게 된다. 또한, 생성자를 이용해서 서비스를 생성하는 이유도 테스트에 용이하기 위함이라는 걸 알게 되었다.

서비스 단위 테스트 시에 모킹한 값이나 필요한 값들을 쉽게 쉽게 넣어줄 수 있으니 생성자를 이용한 서비스 객체 생성이 더욱 용이한 방식이라고 느껴진다.

profile
모르면 쓰지 말고 쓸 거면 알고 쓰자

0개의 댓글