Spring에서는 API를 호출할 수 있는 많은 REST Client를 제공한다.
그 중에서도 WebClient가 가장 많이 추천되는 편이다.
Spring 팀에서도 RestTemplate의 대안으로 WebClient를 추천하고 있고, Reactive 환경과 MSA를 생각하고 있다면, WebClient는 좋은 대안이 될 것이다.
그럼 이러한 WebClient로 작성한 서비스는 어떻게 테스트 코드를 작성할 수 있을까?
두가지 방법이 존재한다.
- Mockito를 사용하는 방법
- 실제 WebClient를 사용하고, MockWebServer를 호출하는 방법
Mockito를 이용해 일일히 stubbing하는 방법도 있지만, 이 방법은 너무 번거롭고 복잡하다.
또한, 테스트하려는 서비스가 WebClient 동작방식에 대해 디테일하게 정의하고 mocking 해줘야하기 때문에 그리 좋은 방법이라고 볼 수 없다.
이 대안으로 MockWebServer를 활용한 테스트 방법이 있다.
MockWebServer를 연동하면, 테스트코드가 실제로 로컬에 있는 MockWebServer의 엔드포인트로 호출을 한다.
Spring 팀에서도 통합테스트 코드 작성 시 MockWebServer의 사용을 권장하고 있다.
그러면 MockWebServer의 사용법을 알아보자.
MockWebServer 라이브러리 추가
testImplementation("com.squareup.okhttp3:okhttp:4.9.1")
testImplementation("com.squareup.okhttp3:mockwebserver:4.9.1")
테스트 대상 Service 코드
@Service
class SampleService(
private val webClient: WebClient
) {
fun callExternalPostApi(request: String, externalApiUrl: String): String? {
return webClient.post()
.uri(externalApiUrl)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(request)
.retrieve()
.bodyToMono(String::class.java)
.block()
}
}
MockWebServer 초기화
val webClient = WebClient.create() // webClient 생성
val sampleService = SampleService(webClient = webClient) // 테스트 서비스 대상에 webclient 주입
lateinit var mockServer: MockWebServer // mockWebServer 초기화
beforeTest {
mockServer = MockWebServer().also { it.start() }
}
afterTest {
mockServer.shutdown()
}
MockWebServer 사용
describe("MockWebServer request checking") {
val mockServerUrl = mockServer.url("/sample").toString() // set MockWebServer url
val mockResponse = MockResponse()
.setResponseCode(200)
.setHeader("Content-Type", MediaType.APPLICATION_JSON)
.setBody("성공")
mockServer.enqueue(mockResponse)
val result = sampleService.callExternalPostApi("요청값", mockServerUrl)
val sampleServiceRequest = mockServer.takeRequest()
result shouldBe "성공"
sampleServiceRequest.method shouldBe "POST"
sampleServiceRequest.path shouldBe "/sample"
sampleServiceRequest.body.readUtf8() shouldBe "요청값"
}
- `MockResponse()` : WebClient의 Response를 조작할 수 있다.
- `mockServer.enqueue()` : MockWebServer는 queue 방식으로 응답하므로, 테스트 대상을 호출하기 전에 mocking 응답을 큐에 넣어준다.
- `mockServer.takeRequest()` : WebClient를 호출할 때의 request를 capture할 수 있다.
위에서 사용된 샘플의 전체 코드는 여기서 확인할 수 있다.
- 전체 코드 : https://github.com/henry-jo/spring-mock-web-server
'Programming > Java & JSP & Spring' 카테고리의 다른 글
JVM 메모리 누수 트러블슈팅 (Native memory leak) (1) | 2024.11.16 |
---|---|
[Spring] Guava RateLimiter 사용법 (spring throttling) (0) | 2022.03.20 |
[Spring boot] Hikari CP 적용 & 커넥션 누수 이슈 (0) | 2022.02.01 |
[Spring] REQUIRES_NEW과 Exception (REQUIRES_NEW는 정말 독립적인가?) (0) | 2020.10.17 |
나만의 코딩컨벤션 작성하기(Spring, Java, Naming, 구조, 코드 작성법 등) (2) | 2020.04.04 |