ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Robolectric] ActivityScenario 오류- java.lang.RuntimeException: Unable to resolve activity for Intent
    TDD 2021. 8. 12. 22:49

    Robolectric을 다시 배워보고자 공부를 시작했다.

     

    Activity에서 사용하는 findViewById를 ActivityScenario에서 제공한다는 것을 알게되었고,

    예제를 그대로 따라서 작성하였다.

    그리고 부푼 마음으로 테스트를 실행해본 결과는 나의 기대와 달리 실패였고, 나는 다음과 같은 오류를 만나게 되었다.

     

    java.lang.RuntimeException: Unable to resolve activity for Intent { cmp=xxxxxxxx/.pos.test.TestMainActivity } -- see https://github.com/robolectric/robolectric/pull/4736 for details

    at org.robolectric.android.fakes.RoboMonitoringInstrumentation.startActivitySyncInternal(RoboMonitoringInstrumentation.java:52)
    at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:40)
    at androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:231)
    at androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:209)
    at com.ttos.imageload.ExampleUnitTest.testScenario(ExampleUnitTest.java:73)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    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.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:575)
    at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:278)
    at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:832)

     

    처음에 나는 이 오류를 보고 매우 당황했지만,늘 해왔듯이 오류에 적힌

    -- see https://github.com/robolectric/robolectric/pull/4736 for details

    이 링크를 타고 들어가기로 헀다.

    들어가 보니, 나와 같은 사례를 겪은 사람들이 글을 만들어 해결방법에 관해 토론하고 있었다.

    원인이 무엇인가 하니,안드로이드에서 test 폴더에서 작성된 AndroidManifest를 자동으로 병합해주지 않아서 생기는 문제라는 것 같다.

    뭔소린 지도 잘 모르겠고, 일단은 여기서 제시하는 해결책을 따라해 보았으나 오류를 해결하는 데 큰 도움이 되지는 않았다.아랫사람이 단 코멘트를 읽어보니

     

    처음 제시된 방법은 더 이상 사용되지 않고, 적절한 방식으로 해결하려면 안드로이드에서 제공하는 flavors를 이용하여 소스 디렉토리를 분리하고, 그 폴더 안에 추가하라는 말이었다.

     

    Android Flavors라는 것에 대해 나는 들어본 적도 없어 생소했으나,

    우선은 나름대로 조사해본 결과 같은 어플리케이션을 여러가지 버전에 따라 다르게 빌드할 수 있는 환경을 만들어주는 방법이라는 것 같다.

    그래서 일단 다른 블로그 포스팅을 보고 따라해보았다.

    android{
    ....
    flavorDimensions "test"
        productFlavors {
            app {
                versionCode 10
                versionName '1.1.6'
            }
            integrationTest {
                versionCode 10
                versionName '1.1.6'
            }
        }
        ...
       }

    우선 app 수준의 build.gradle 파일에 다음 내용을 추가해 주었다.

    조사해 본 바에 의하면 flavorDimensions는 각 productFlavors들이 속하는 차원이고,

    이름지어진 각 productFlavors 안에 해당 Flavor로 빌드할 시 달라질 점을 명시할 수 있다는 것 같다.

    우선 나는 app과 integrationTest를 만들었다.(test로 만들려고 했으나, 이름이 겹친다는 오류가 발생하여 바꾸었다.)

    추가하고 Sync하고 나면,스튜디오 좌측 하단에 위치한 Build Variants라는 탭에서 Active Build Variant에 

    아까 추가한 app과 integrationTest가 각기 Debug 버전과 Release 버전으로 나뉘어지는 것을 확인할 수 있다.

    그리고 추가적으로 해줘야 할 것은 main과 test버전의 sourceSets를 나누는 것이다.

    우선 위에서 말했던 원인이 AndroidManifest를 자동으로 병합해주지 않아서 생기는 문제라고 하니,

    우선 main 폴더의 AndroidManifest 파일을 test 폴더로 복사하였다.

    android
    {
    ...
    sourceSets {
            main {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java.srcDirs = ['src/main/java']
                res.srcDirs = ['src/main/res']
            }
            integrationTest {
                manifest.srcFile 'src/test/AndroidManifest.xml'
                java.srcDirs = ['src/main/java']
                res.srcDirs = ['src/main/res']
            }
        }
        ...
        }

    위 코드 또한 앱 수준의 build.gradle 파일에 추가해준다.

    integrationTest는 아까 만들었던 test용 Flavor 이름이다. 일치시켜주도록 한다.

    유의해야 할 것은 integrationTest의 srcDir과 res.srcDir의 경로는 src/main~으로 해주도록 한다.

    그렇지 않으면 테스트 폴더가 Robolectric을 인식하지 못하기 때문이다.

    Sync를 해주고 Build Variant에서 integrationDebug로 설정한 뒤,

    다시 테스트를 실행하면

    깔끔하게 테스트를 통과하는 걸 확인할 수 있다.

    부족한 글솜씨를 양해해주길 바라며, 도움이 되기를 바란다!

Designed by Tistory.