【问题标题】:Espresso test failing with progress dialog not removed from top浓缩咖啡测试失败,进度对话框未从顶部删除
【发布时间】:2017-07-25 07:45:52
【问题描述】:

我正在为我的应用编写 Espresso 测试。当我运行它时,我的一项测试失败了,当它被调试时它工作正常。这似乎是一个线程问题。调用 api 时,代码首先显示 ProgressDialog,当收到响应时将其删除。测试失败表示运行此测试时仍显示进度对话框。

测试是:

@Rule
    public IntentsTestRule<ScrDoctorHomeNew> activityTestRule = new IntentsTestRule<>(ScrDoctorHomeNew.class,false,false);

@Test
    public void testRecommendationCountIOException() {
        ApiFactory.INSTANCE.setErrorObservable(Observable.error(new IOException("Network Error")));

        activityTestRule.launchActivity(null);

        onView(withId(R.id.lblOldRecommandation)).check(matches(withText(String.format(activityTestRule.getActivity().getString(R.string.txt_doctor_old_recommandation), 0))));
    }

显示进度对话框的片段

private void fetchProfileData() {
        if (mActivity != null) {
            mActivity.showProgressDialogInUiThread(mActivity.getResources().getString(R.string.str_loading));
        }
        ApiFactory.INSTANCE.getDocProfileRetriever().getProfile(LocalDataManager.getInstance().getUser().getUserId()).subscribe(
                new Subscriber<ProfileMessage>() {
                    @Override
                    public void onCompleted() {
                        if (mActivity != null) {
                            mActivity.dismissProgressDialogInUiThread();
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (mActivity != null) {
                            mActivity.dismissProgressDialogInUiThread();
                        }
                        updateRecommendationCount(0);
                        Log.e(HomeFragment.class.getSimpleName(),"Exception:",e);
                    }

                    @Override
                    public void onNext(ProfileMessage profileMessage) {
                        if (profileMessage != null) {
                            ArrayList<String> list = profileMessage.getProblemRecommendations();
                            if (list != null) {
                                updateRecommendationCount(list.size());
                            } else {
                                updateRecommendationCount(0);
                            }
                        } else {
                            updateRecommendationCount(0);
                        }
                    }
                });
    }

BaseActivity 显示进度对话框

public void showProgressDialogInUiThread(String text) {
        mProgressDlgFragment =
                ProgressDialogFragment.getInstance(false, false, text,
                        R.style.ProgressDialogStyle);
        mProgressDlgFragment.show(getSupportFragmentManager(), ProgressDialogFragment.DIALOG_TAG);

    }

    public void dismissProgressDialogInUiThread() {
        if (mProgressDlgFragment != null) {
            mProgressDlgFragment.dismiss();
        }
    }

显示的错误是:

android.support.test.espresso.NoMatchingViewException:在层次结构中找不到匹配的视图:id:tk.swapnilUtilities.eRecommendationAndroid:id/lblOldRecommandation

查看层次结构: +>DecorView{id=-1, visibility=VISIBLE, width=480, height=854, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled =true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0 , y=0.0, 子数=1} | +->LinearLayout{id=-1, visibility=VISIBLE, width=480, height=854, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-已启用=true,is-focused=false,is-focusable=false,is-layout-requested=false,is-selected=false,root-is-layout-requested=false,has-input-connection=false,x= 0.0, y=0.0, 子数=2} | +-->ViewStub{id=16909149, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-启用=真,聚焦=假,可聚焦=假,布局请求=真,被选择=假,根是布局请求=假,输入连接=假,x = 0.0, y=0.0} | +-->FrameLayout{id=16908290, res-name=content, visibility=VISIBLE, width=480, height=816, has-focus=false, has-focusable=false, has-window-focus=true, is- clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-连接=假,x=0.0,y=38.0,子计数=1} | +--->RelativeLayout{id=-1, visibility=VISIBLE, width=480, height=816, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, 子数=1} | +---->LinearLayout{id=-1, visibility=VISIBLE, width=480, height=187, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false , is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false , x=0.0, y=314.0, 孩子数=2} | +----->CustomProgressIndicator{id=2131558672, res-name=progress_indicator, visibility=VISIBLE, width=114, height=114, has-focus=false, has-focusable=false, has-window-focus=true , is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, 有-输入连接=假,x=183.0,y=0.0,子计数=2} | +-------->ImageView{id=2131558674, res-name=progress_indicator_view_inner, visibility=VISIBLE, width=114, height=114, has-focus=false, has-focusable=false, has-window-focus= true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false,有输入连接=假,x=0.0,y=0.0} | +------>ImageView{id=2131558675, res-name=progress_indicator_view_outer, visibility=VISIBLE, width=114, height=114, has-focus=false, has-focusable=false, has-window-focus= true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false,有输入连接=假,x=0.0,y=0.0} | +----->TextView{id=2131558673, res-name=tv_message, visibility=VISIBLE, width=129, height=49, has-focus=false, has-focusable=false, has-window-focus=true , is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, 有-input-connection=false, x=175.0, y=138.0, text=Loading, input-type=0, ime-target=false, has-links=false} | 在 dalvik.system.VMStack.getThreadStackTrace(本机方法) 在 java.lang.Thread.getStackTrace(Thread.java:579) 在 android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:92) 在 android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:56) 在 android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184) 在 android.support.test.espresso.ViewInteraction.check(ViewInteraction.java:158) 在 tk.swapnilUtilities.eRecommendationAndroid.ui.ScrHomeNewTest.testRecommendationCountIOException(ScrHomeNewTest.java:59) 在 java.lang.reflect.Method.invokeNative(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:525) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 在 android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.java:55) 在 android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:270) 在 org.junit.rules.RunRules.evaluate(RunRules.java:20) 在 org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:363) 在 org.junit.runners.Suite.runChild(Suite.java:128) 在 org.junit.runners.Suite.runChild(Suite.java:27) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:363) 在 org.junit.runner.JUnitCore.run(JUnitCore.java:137) 在 org.junit.runner.JUnitCore.run(JUnitCore.java:115) 在 android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59) 在 android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262) 在 android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1667)

[编辑]我已禁用动画,但结果仍然相同。我正在使用模拟模式来模拟收到的响应。立即返回模拟错误响应。手动运行应用程序后,我观察到在我的应用程序被发送到后台之前,进度对话框不会被删除。

谁能指出我该如何解决这个错误?

【问题讨论】:

    标签: android android-espresso


    【解决方案1】:

    至少有几件事可能。

    1. 确保在运行测试之前禁用动画。您可能已经这样做了,但不清楚,值得向其他读者指出。

    “为避免片状,我们强烈建议您关闭系统 用于测试的虚拟或物理设备上的动画。

    在您的设备上,在“设置”->“开发者选项”下禁用 以下3个设置: 窗口动画比例 过渡动画 scale Animator 持续时间比例"

    https://google.github.io/android-testing-support-library/docs/espresso/setup/


    1. 另一件事(很可能是问题所在)是测试在收到响应之前完成。如果进度条仍然存在,这是有道理的。解决方案是使用 Espresso IdlingResource。

    “Espresso 的核心是其无缝同步的能力 正在测试的应用程序的所有测试操作。默认, Espresso 等待当前消息队列中的 UI 事件 处理并让默认 AsyncTasks 在继续之前完成 下一个测试操作。

    但是,在某些情况下,应用程序执行后台 通过非标准的操作(例如与 Web 服务通信) 方法;例如:直接创建和管理线程。

    在这种情况下,您必须使用空闲资源通知 Espresso 应用程序的长期运行。”

    https://google.github.io/android-testing-support-library/docs/espresso/idling-resource/index.html


    如果文档不够清晰 - 或者,请查看代码实验室 https://codelabs.developers.google.com/codelabs/android-testing

    有几个示例说明如何使用 Idling 资源。它有几部分,所以我建议您看一下以节省一些时间。如果没有别的,至少看看源代码。

    【讨论】:

    • 我已禁用动画,但结果仍然相同。我正在使用模拟模式来模拟收到的响应。立即返回模拟错误响应。
    • 您是否尝试过在 withId 部分之前使用“descendentOf”?我不知道布局是什么样的,但有时这会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-15
    相关资源
    最近更新 更多