Instrumental Testing with FragmentScenario

后端 未结 3 2166
伪装坚强ぢ
伪装坚强ぢ 2021-02-14 21:27

I\'m trying to use the new FragmentScenario APIs of the androidx testing libraries for local testing and instrumentation testing(androidTest). The api works fine in local enviro

相关标签:
3条回答
  • 2021-02-14 21:53

    You need to add "fragment-testing" dependency to the APK under testing instead of test APK.

    So please update your build.gradle to

    debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
    

    from

    androidTestImplementation "androidx.fragment:fragment-testing:$fragment_version"
    

    (This is due to implementation details of FragmentScenario. "fragment-testing" declares Activity and is used by FragmentScenario. Activities declared in test APK runs in different process from APK under testing. In order to execute Fragment's code in the same process, you need to put "fragment-testing" library into your APK, not in test APK.)

    Here's also a tutorial page in developers site.

    0 讨论(0)
  • 2021-02-14 21:56

    In my case the activity that the fragment is launched in, EmptyFragmentScenario, could not be opened because of a

    Caused by: java.lang.ClassNotFoundException: Didn't find class androidx.fragment.app.testing.FragmentScenario$EmptyFragmentActivity
    

    See the full stacktrace:

    2018-12-12 02:12:46.529 32659-32659/? E/AndroidRuntime: FATAL EXCEPTION: main
        Process: app.debug.test, PID: 32659
        java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{app.debug.test/androidx.fragment.app.testing.FragmentScenario$EmptyFragmentActivity}: java.lang.ClassNotFoundException: Didn't find class "androidx.fragment.app.testing.FragmentScenario$EmptyFragmentActivity" on path: DexPathList[[zip file "/system/framework/android.test.mock.jar", zip file "/system/framework/android.test.runner.jar", zip file "/data/app/app.debug.test-HdSyMEsvYzlt1aceQIeIuw==/base.apk"],nativeLibraryDirectories=[/data/app/app.test-HdSyMEsvYzlt1aceQIeIuw==/lib/arm64, /system/lib64, /vendor/lib64]]
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2843)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loop(Looper.java:193)
            at android.app.ActivityThread.main(ActivityThread.java:6669)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
         Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.fragment.app.testing.FragmentScenario$EmptyFragmentActivity" on path: DexPathList[[zip file "/system/framework/android.test.mock.jar", zip file "/system/framework/android.test.runner.jar", zip file "/data/app/app.debug.test-HdSyMEsvYzlt1aceQIeIuw==/base.apk"],nativeLibraryDirectories=[/data/app/app.debug.test-HdSyMEsvYzlt1aceQIeIuw==/lib/arm64, /system/lib64, /vendor/lib64]]
            at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
            at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
            at android.app.Instrumentation.newActivity(Instrumentation.java:1215)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2831)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) 
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) 
            at android.os.Handler.dispatchMessage(Handler.java:106) 
            at android.os.Looper.loop(Looper.java:193) 
            at android.app.ActivityThread.main(ActivityThread.java:6669) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
            Suppressed: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/fragment/app/FragmentActivity;
            at java.lang.VMClassLoader.findLoadedClass(Native Method)
            at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:738)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:363)
                    ... 15 more
         Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.fragment.app.FragmentActivity" on path: DexPathList[[zip file "/system/framework/android.test.mock.jar", zip file "/system/framework/android.test.runner.jar", zip file "/data/app/app.debug.test-HdSyMEsvYzlt1aceQIeIuw==/base.apk"],nativeLibraryDirectories=[/data/app/app.debug.test-HdSyMEsvYzlt1aceQIeIuw==/lib/arm64, /system/lib64, /vendor/lib64]]
            at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
                    ... 18 more
    

    I couldn't find the correct dependency I need in order for that EmptyFragmentActivity to be included at runtime so my temporary workaround was to not use launchFragmentInContainer and instead launch my own Activity:

    My test activity:

    class TestFragmentActivity : AppCompatActivity() {
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
      }
    
      fun replaceFragment(fragment: Fragment) {
        supportFragmentManager
            .beginTransaction()
            .replace(android.R.id.content, fragment)
            .commit()
      }
    }
    

    My test:

    @RunWith(AndroidJUnit4::class)
    class MyFragmentAndroidTest {
    
      @get:Rule val activityRule: ActivityTestRule<TestFragmentActivity> =
          ActivityTestRule(TestFragmentActivity::class.java)
    
      @Test
      fun test() {
        activityRule.activity.replaceFragment(MyFragment.newInstance())
    
        onView(withId(R.id.title)).check(matches(withText("Title"))))
        // More assertions.
      }
    }
    
    0 讨论(0)
  • 2021-02-14 22:14

    I believe there is a limitation within the launch(Intent startActivityIntent) method of ActivityScenario. It only wants the Activity to be RESUMED or DESTROYED and if it isn't within 4.5 seconds then it throws that error.

    Within public static <A extends Activity> ActivityScenario<A> launch(Intent startActivityIntent) of Activity Scenario, check the logic scenario.waitForActivityToBecomeAnyOf(State.RESUMED, State.DESTROYED);

    EDIT This issue has been fixed.

    0 讨论(0)
提交回复
热议问题