Espresso 测试导致 "ClassNotFoundException when unmarshalling"(在基本应用程序上重现)

Espresso tests cause "ClassNotFoundException when unmarshalling" (REPRODUCED on basic app)

在 espresso 测试期间使用保存的实例状态重新创建 activity 时,似乎总是会抛出此解组异常。我用一个非常基本的 android 应用程序复制了它。以下是步骤:

  1. 创建一个 android 应用,其中包含两个 Activity,每个 Activity 都有一个按钮。第一个 activity 上的按钮打开第二个 activity。第二个 activity 上的按钮关闭当前 activity.

  2. 添加一个浓缩咖啡测试,只需打开第一个 activity,点击按钮(打开第二个 activity),然后点击第二个 [=43] 上的按钮=](完成第二个 activity 并返回第一个 activity)。

  3. 在您的模拟器上,确保启用“不保留活动”。

在我的真实应用程序中,它因 activity 而异,class 将“未知”导致解组。在这个具体的例子中,它显然是工具栏。我发现通过从保存的实例状态中删除特定条目(“androidx.lifecycle.BundlableSavedStateRegistry.key”和“android:viewHierarchyState”),它将在浓缩咖啡测试期间解决此异常,但当然事情不会得到正确恢复。我要重申,这只是 运行 espresso 测试时的一个问题。当手动执行完全相同的测试步骤时,一切都正确解组并且没有异常。

更改 sdk 版本似乎也无济于事。

就是这样。

以下是所有血淋淋的代码:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
//        // This will cause the exception to not be thrown during espresso tests
//        if(savedInstanceState != null) {
//            savedInstanceState.remove("androidx.lifecycle.BundlableSavedStateRegistry.key");
//            savedInstanceState.remove("android:viewHierarchyState");
//        }
        

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.open_button).setOnClickListener(v -> startActivity(new Intent(MainActivity.this, ChildActivity.class)));
    }
}
public class ChildActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_child);

        findViewById(R.id.close_button).setOnClickListener(v -> finish());
    }
}
@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

    @Rule
    public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void test() {
        onView(withId(R.id.open_button)).perform(click());
        onView(withId(R.id.close_button)).perform(click());
        onView(withId(R.id.open_button)).check(matches(isDisplayed()));
    }
}
androidx.test.espresso.PerformException: Error performing 'single click - At Coordinates: 115, 272 and precision: 16, 16' on view 'view.getId() is <2131231192/com.example.myapplication:id/close_button>'.
    at androidx.test.espresso.PerformException$Builder.build(PerformException.java:1)
    at androidx.test.espresso.base.PerformExceptionHandler.handleSafely(PerformExceptionHandler.java:8)
    at androidx.test.espresso.base.PerformExceptionHandler.handleSafely(PerformExceptionHandler.java:9)
    at androidx.test.espresso.base.DefaultFailureHandler$TypedFailureHandler.handle(DefaultFailureHandler.java:4)
    at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:5)
    at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:8)
    at androidx.test.espresso.ViewInteraction.desugaredPerform(ViewInteraction.java:11)
    at androidx.test.espresso.ViewInteraction.perform(ViewInteraction.java:8)
    at com.example.myapplication.MainActivityTest.mainActivityTest(MainActivityTest.java:31)
    ... 32 trimmed
Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: androidx.appcompat.widget.Toolbar$SavedState
    at android.os.Parcel.readParcelableCreator(Parcel.java:2839)
    at android.os.Parcel.readParcelable(Parcel.java:2765)
    at android.os.Parcel.readValue(Parcel.java:2668)
    at android.os.Parcel.readSparseArrayInternal(Parcel.java:3118)
    at android.os.Parcel.readSparseArray(Parcel.java:2351)
    at android.os.Parcel.readValue(Parcel.java:2725)
    at android.os.Parcel.readArrayMapInternal(Parcel.java:3037)
    at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:288)
    at android.os.BaseBundle.unparcel(BaseBundle.java:232)
    at android.os.Bundle.getSparseParcelableArray(Bundle.java:1010)
    at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2133)
    at android.app.Activity.onRestoreInstanceState(Activity.java:1135)
    at android.app.Activity.performRestoreInstanceState(Activity.java:1090)
    at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1317)
    at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2953)
    at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
    at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at androidx.test.espresso.base.Interrogator.loopAndInterrogate(Interrogator.java:14)
    at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:8)
    at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:1)
    at androidx.test.espresso.base.UiControllerImpl.injectMotionEvent(UiControllerImpl.java:6)
    at androidx.test.espresso.action.MotionEvents.sendUp(MotionEvents.java:7)
    at androidx.test.espresso.action.MotionEvents.sendUp(MotionEvents.java:1)
    at androidx.test.espresso.action.Tap.sendSingleTap(Tap.java:5)
    at androidx.test.espresso.action.Tap.sendSingleTap$bridge(Unknown Source:0)
    at androidx.test.espresso.action.Tap.sendTap(Tap.java:3)
    at androidx.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:6)
    at androidx.test.espresso.ViewInteraction$SingleExecutionViewAction.perform(ViewInteraction.java:2)
    at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:25)
    at androidx.test.espresso.ViewInteraction.doPerform$bridge(Unknown Source:0)
    at androidx.test.espresso.ViewInteraction.call(ViewInteraction.java:2)
    at androidx.test.espresso.ViewInteraction.call(ViewInteraction.java:1)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    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)

据我所知,您应该改为使用 ActivityScenario 和 然后使用 ActivityScenario.moveToState or ActivityScenario.recreate.

测试不同活动的状态