본문 바로가기
[Developer]/Android

[번역] 단위테스트를 위한 안드로이드 모의 서버

by 해피빈이 2020. 7. 27.

본 포스팅은 Elye의 Android Mock Server for UnitTest를 번역하여 작성하였습니다.

(원어 부제: Make unit test for network fetching easier)


Photo from Pixabay(아수트리아스 선셋 하늘)

 

오늘날 우리가 구축하는 거의 모든 앱은 서버에서 무언가를 가져온다. 다양한 서비스 조건을 흉내낼 수 있는 모의 페이로드 혹은 더 나은 모의 서버로 로직을 단위테스트 할 수 있다면 얼마나 좋을까. 이것에 대한 좋은 소식으로는, OkHttp 라이브러리를 제공한 Square에서도 그들의 OkHttp를 위한 MockWebServer를 가지고 있다는 점이다.

 

Square의 MockWebServer

 

square/okhttp

Square’s meticulous HTTP client for Java and Kotlin. - square/okhttp

github.com

 

설정

라이브러리 의존성

분명히 말하지만, 이것을 사용하려면 이미 OkHttp를 사용하고 있어야 한다.(이는 Retrofit을 사용하는 경우도 적용된다.) 그런 다음 앱의 build.gradle 파일에 Mock Web Server 라이브러리를 추가하기만 하면 된다.

 

implementation 'com.squareup.okhttp3:okhttp:4.8.0'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.3.1'

 

Mock Server 인스턴스화

아래는 var server = MockWebServer()로 인스턴스화 하는 방법이다. 그리고 시작할 때 server.start()를 하고, 끝날 때는 server.shutdown()를 하면 된다.

 

가져오는 것(fetching)을 수행하는 Chat 클래스가 있다고 가정하면, 아래에서 보여주는 것처럼 서버의 url을 설정하여 baseUrl을 얻어올 필요가 있다.

private var server = MockWebServer()
private lateinit var chat: Chat
@Before
fun setup() {
    server.start(port)
    val baseUrl: HttpUrl = server.url(path)
    chat = Chat(baseUrl)
}

@After
fun tearDown() {
    server.shutdown()
}

이제 당신은 여러 가능한 웹 서비스들의 응답을 테스트 할 준비가 되었다.

 

모의 웹 서비스

Body와 함께 모의 성공 응답

이것은 당신이 좋아하는 형태의 Body를 제공하는 가장 일반적인 것이다.

server.enqueue(MockResponse().setBody("{ result: \"success\" }")

만약 당신이 JSON 파일 결과로부터 body를 얻어오는 것을 좋아한다면, 아래의 글을 확인해보라.

Android Reading a Text File during Test

 

Android Reading a Text File during Test

Useful to create mock JSON results etc.

medium.com

 

모의 응답 헤더

만약 당신이 헤더를 다시 받으려면 아래와 같이 추가하라.

val response = MockResponse()
    .addHeader("Content-Type", "application/json; charset=utf-8")
    .addHeader("Cache-Control", "no-cache"))
server.enqueue(response)
팁: 쿠키를 설정하는 방법으로는, 헤더를 통해서 할 수 있다.
val response = MockResponse()
    .addHeader("Cookie", "cookie1=some-value; cookie2=other-value"))
server.enqueue(response)

 

모의 여러 응답들

때때로 당신은 다른 응답들을 테스트 하기 원한다.(같은 URL로부터 가져오는 경우에) 그땐 당신은 set이나 enqueue 응답을 제공할 수 있다.

server.enqueue(MockResponse().setBody("first result"))
server.enqueue(MockResponse().setBody("second result"))
server.enqueue(MockResponse().setBody("final result"))

 

조건부적인 응답과 함께 모의 설정

당신이 서버에 호출할 때 다른 경로를 가정하면, 다르게 응답할 것이다. 그것은 디스패처를 사용하는 것으로 모의처리가 가능하다.

val dispatcher: Dispatcher = object : Dispatcher() {
    override fun dispatch(request: RecordedRequest): MockResponse {
        when (request.path) {
            "/v1/path1" 
               -> return MockResponse().setResponseCode(204)
            "/v1/path2" 
               -> return MockResponse().setResponseCode(200)
                .setBody("good")
        }
        return MockResponse().setResponseCode(404)
    }
}
server.dispatcher = dispatcher

 

웹 서비스 에러 모의 설정

당신이 원하는 모든 서버 응답 코드를 모의로 할 수 있다.(가령, 300, 400, 404, 500 등) 당신이 필요한 모든 것에 대해서.

server.enqueue(MockResponse().setResponseCode(code))

 

더 느린 서비스를 모의 설정

당신은 타임아웃 핸들링을 포착하기위해 서비스의 속도를 늦을 수 있다.

server.enqueue(MockResponse().throttleBody(
      bytesPerPeriod = 1, period = 2, unit = TimeUnit.SECONDS)

 

요청 포착하기

서버에 대한 요청을 포착하기 위해, 제공된 takeRequest API를 사용할 수 있다.

val request: RecordedRequest = server.takeRequest()
assertEquals(expectedPath, request.path)
assertNotNull(request.getHeader("Authorization"))

여러개의 후속 요청에 대해 처리하게 할 수도 있다.

val request1: RecordedRequest = server.takeRequest()
assertEquals(path1, request1.path)
val request2: RecordedRequest = server.takeRequest()
assertEquals(path2, request2.path)

 

당신은 이 곳에서 예제 코드를 얻을 수 있다.

 

그리고 자신의 JSON Response를 작성하는 것이 귀찮아 지는 경우, 아래를 참고해 보아라.

Instrumental Test: Record and reply your network payload

 

Instrumental Test: Record and replay your network payload

Ever wonder how nice if you could record your network fetch payload and replay it? This blog will talk about it, makes your Instrumental…

medium.com

 

반응형

댓글