우리 팀에서 관리하는 서버 중에 외부의 이미지를 수집하기 위해 이미지 URL을 받아 이를 우리가 원하는 사이즈로 가공하여 S3에 업로드하는 역할을 하는 서버가 있다.
이러한 프로세서에 대해 테스트코드를 작성하고자 하니,, 문제점이 있었다. 이미지 URL은 언제든 깨질 수 있어 테스트코드 작성 시 가장 중요한 원칙 중 하나인 멱등성 보장이 어려웠다.
그래서 이미지를 받아오는 외부 서버와 통신하는 부분을 모킹서버를 활용해 해결하였다.
처음에 두가지 라이브러리 중 고민을 하였다.
MockServer Netty
okhttp MockWebServer
스프링 진영에서는 okhttp MockWebServer
를 활용해 모킹서버를 구축하는 것을 권장(링크)한다고 하여 okhttp MockWebServer
를 사용하게 됐다.
// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
testImplementation 'com.squareup.okhttp3:okhttp:4.10.0'
// https://mvnrepository.com/artifact/com.squareup.okhttp3/mockwebserver
testImplementation 'com.squareup.okhttp3:mockwebserver:4.10.0'
public class MockServer
{
private final MockWebServer mockWebServer;
public MockServer() throws IOException
{
this.mockWebServer = new MockWebServer();
this.mockWebServer.start();
}
public void shutdown() throws IOException
{
this.mockWebServer.shutdown();
}
public String getMockServerBaseUrl()
{
return "http://localhost:" + this.mockWebServer.getPort();
}
public void insertNormalImageResponse()
{
try
{
this.mockWebServer.enqueue(new MockResponse()
.addHeader("Content-Type:image/png")
.setBody(getBinaryFileAsBuffer("seed/image/normal-image.jpg")));
} catch (Exception e)
{
e.printStackTrace();
}
}
public static Buffer getBinaryFileAsBuffer(String path) throws IOException {
ClassPathResource classPathResource = new ClassPathResource(path);
byte[] fileData = FileUtils.readFileToByteArray(classPathResource.getFile());
Buffer buf = new Buffer();
buf.write(fileData);
return buf;
}
}
insertNormalImageResponse
메서드를 보면 mockserer
에 큐를 넣듯 내가 기대하는 MockResponse
를 넣는 것을 볼 수 있다.
그렇다! MockWebServer
는 어떤 url이든 베이스 URL
을 호출하면 사전에 큐에 넣어둔 response를 FIFO
처럼 차근차근 꺼내 보여주는 방식으로 모킹한다.
class ...Test {
private MockServer mockServer;
@BeforeEach
void beforeTest() throws IOException
{
this.mockServer = new MockServer();
}
@AfterEach
void afterTest() throws IOException
{
this.mockServer.shutdown();
}
@Test
@DisplayName("만약 URL이 정상이여서 다운로드 가능하다면 다운로드에 성공한다.")
void successWhenItDownload()
{
// given
mockServer.insertNormalImageResponse();
String url = mockServer.getMockServerBaseUrl();
// when
테스트대상.download(url);
...
// then
...
}
}
given
절에서 MockServer
큐에 내가 기대하는 response를 넣었고, 이를 when 절에서 해당 모킹서버와 통신하면 기대하는 response가 나오는 구조이다.