Junit4으로 Retrofit 테스트 해보기
0. 주저리 주저리
예전부터 해보고 싶은 것중 하나는 테스트 코드를 작성해보고 싶었고, 그것을 빌미로 프로젝트를 진행해보고 싶었다. 이런 방법을 TDD라고 하는 것 같았고, 항상 그런 정보를 접할 때마다 공부를 하고 싶었다. 그래서, TDD 방법론까지는 아니지만, 테스트 코드를 맛보기 위해서
RxJava + Retrofit2 => Test based Junit4
으로 작성된 테스트 코드를 만들어보려고 한다.
1. 1단 해야할 것들
1-1. 참고 사이트
https://developer.android.com/training/testing/unit-testing/local-unit-tests
https://www.vogella.com/tutorials/AndroidTesting/article.html
1-2. 모듈
1 2 3 | testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' | cs |
2. 안드로이드를 실행할 때마다, 봤던 Test Folder들은 무엇일까?
어플리케이션을 만들 때마다, androidTest, test와 같은 폴더들이 만들어지고, 우리는 평상시와 똑같이 녹색 부분을 감춘채, MainActivity를 코딩하기 시작합니다. 그런데, 신기한게 이러한 폴더들이 특정 Test를 실행하기 위해서 구분되었다고 합니다.
경로 |
역할 |
|
app/src/main |
Main Application이 빌드되는 위치 |
|
app/src/test |
JVM에서 Unit Test를 할 수 있는 위치 |
|
app/src/androidTest |
Android device에서 Test할 수 있는 위치 |
우리가 항상 코드를 작성하는 app/src/main에서는 Application이 빌되는 위치이며, 그 외에 Test의 분류는 JVM단에서 Unit Test를 하는 것과 Android device에서 물리적으로 Test할 수 있는 2가지 테스트가 있다는 것을 알 수 있습니다.
3. 시작이 절반이다.
3-1. app/src/main/CalculatorUtil.kt
1 2 3 | class CalculatorUtil { fun plus(a:Int, b:Int) : Int = a+b } | cs |
3-2. app/src/test/ExampleUnitTest.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class ExampleUnitTest { private lateinit var calculatorUtil : CalculatorUtil @Before fun initialize(){ println("Start") calculatorUtil = CalculatorUtil() } @Test fun plus(){ val sum = calculatorUtil.plus(10,10) assertEquals(sum, 20) } @After fun finish(){ println("Finish") } } | cs |
4. 생각보다 자유롭지 않은 Test Code
4-1. Test로 Log 찍기
1 2 3 4 5 6 | class ExampleUnitTest { @Test fun 안녕하세요(){ Log.d("hello","hello") } } | cs |
아래와 같이 Method d가 mocked 되지 않았다면서, 오류를 출력하는 것을 볼 수 있었습니다. 그러한 이유는 static과 같은 싱글톤은 Test Code를 힘들다는 얘기를 들었는데, Log와 같은 static 클래스가 이와 같은 것을 알게 되었습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | java.lang.RuntimeException: Method d in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details. at android.util.Log.d(Log.java) at hbs.com.androidstudy.ExampleUnitTest.안녕하세요(ExampleUnitTest.kt:21) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) | cs |
5. 우선, static을 피해서 각종 객체 접근하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class ExampleUnitTest { private lateinit var jobCafeUseCase: JobCafeUseCase @Before fun setupTest() { jobCafeUseCase = JobCafeUseCaseImpl( JobCafeRepositoryImpl( RetrofitProvider.provideSeoulApi() ) ) } @Test fun getJobCafe() { jobCafeUseCase .getJobCafeList() .subscribe { wrappingJobCafeList -> println(wrappingJobCafeList.jobCafeList.jobCafes.toString()) } } } | cs |
위와 같은 방식으로 retrofit의 객체를 만들어서 Test를 해본 결과 정상적으로 작동하는 것을 알 수 있었습니다.
추후 수정 예정/
- https://www.vogella.com/tutorials/AndroidTesting/article.html#androidtesting_projectstructure [본문으로]
'Android 공부 > Android Library Study' 카테고리의 다른 글
Android Worker - 매일 알람 만들기 (0) | 2019.11.09 |
---|---|
인앱결제 - 구매후 생각해야 할 것 (3) | 2019.11.09 |
안드로이드 인앱결제 - 구매 로직 (2) | 2019.11.09 |
서울시 공공데이터 API를 활용한 Paging Library 사용하기 - 2 (0) | 2019.08.19 |
서울시 공공데이터 API를 활용한 Paging Library 사용하기 - 1 (0) | 2019.08.18 |