Android Espresso Intents测试随机失败,并显示``必须先调用init()才能使用此方法'' [英] Android Espresso Intents test randomly fail with ``init() must be called prior to using this method``

查看:168
本文介绍了Android Espresso Intents测试随机失败,并显示``必须先调用init()才能使用此方法''的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力将一个项目推入浓缩咖啡测试.我已经阅读了一堆文件,并按照给定的方法开始使用.

I am working on pushing a project into espresso testing currently. I have read a bunch of documents and follow the given practises to get started.

一切正常,但是,涉及Intents相关测试时,结果却很奇怪.

Everything works fine, However, when it comes to Intents related test, the result is strange.

大多数时候,测试在我的Mac中通过,但在同事的Windows中失败(并非所有测试都失败),并显示失败消息java.lang.IllegalStateException: init() must be called prior to using this method.

Most of the time, the tests passed in my Mac but fail in my colleague's Windows(not all tests fail) with the the fail message java.lang.IllegalStateException: init() must be called prior to using this method.

奇怪的是,如果我们在Android Studio中运行Debug测试,则代码会一步一步地通过,那么代码就会通过.

Quite strangely, If we Run Debug test in Android Studio flow the code step by step, it passes.

这是测试代码:

@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityTest {

  @Rule public IntentsTestRule<MainActivity> mRule = new IntentsTestRule<>(MainActivity.class, true, false);

  AccountManager accountManager;
  MainActivity   activity;


  private void buildLoginStatus() throws AuthenticatorException {
    DanteApp app = (DanteApp) InstrumentationRegistry.getTargetContext().getApplicationContext();
    accountManager = app.getDanteAppComponent().accountManager();

    DoctorModel doctorModel = AccountMocker.mockDoctorModel();
    accountManager.save(doctorModel.doctor);
    accountManager.setAccessToken(doctorModel.access_token, false);
  }

  @Before public void before() throws Exception {
    buildLoginStatus();

    // must login
    assertThat(accountManager.hasAuthenticated(), is(true));

    activity = mRule.launchActivity(null);
    // block all of the outer intents
    intending(not(isInternal())).respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null));
  }

  @After public void tearDown() throws Exception {
    accountManager.delete();
  }

  // failed
  @Test public void testViewDisplay() throws Exception {

    // check tabhost is displayed
    onView(withClassName(equalTo(TabHost.class.getName()))).check(matches(isDisplayed()));

    // check toolbar is displayed
    onView(withClassName(equalTo(ToolBar.class.getName()))).check(matches(isDisplayed()));
  }

  // passed
  @Test public void testCallServiceHotline() throws Exception {
    // switch to the account tab layout
    onView(withChild(withText(R.string.account))).perform(click());
    // click account menu to make a service call
    onView(withId(R.id.contact)).perform(click());

    // check call start expectly
    intended(allOf(
        not(isInternal()),
        hasAction(Intent.ACTION_DIAL),
        hasData(Uri.parse("tel:" + activity.getString(R.string.call_service)))
    ));
  }


  // failed
  @Test public void testOpenSettingsUI() throws Exception {
    // stub all internal intents
    Intents.intending(isInternal())
        .respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null));

    onView(withChild(withText(R.string.account))).perform(click());
    onView(withId(R.id.setting)).perform(click());

    // check open settings activity successfully
    intended(anyOf(
        hasComponent(SettingActivity.class.getName())
    ));
  }
}

测试库版本(几乎所有依赖项都是最新的,我们同时使用物理设备和仿真器进行测试):

The testing library version(nearly all dependencies are up to date and we use both physics devices and emulator to test):

  • 规则:0.4.1
  • 领跑者:0.4.1
  • espresso- *:2.2.1
  • support- *:23.1.0

任何想法都值得赞赏.谢谢!

Any idea deserves an appreciation. Thanks!

推荐答案

两种解决方案:

  1. 使用ActivityTestRule代替IntentsTestRule,然后分别在@Before和@After中手动调用Intents.init()和Intents.release().
  2. 编写一个自定义的IntentTestRule并覆盖beforeActivityLaunched()以包括您的AccountManager逻辑.将afterActivityFinished用于当前的@After逻辑.这也将允许您只使用默认的IntentTestRule构造函数. (首选解决方案)

关于发生这种情况的原因:

As to why this is happening:

最后要注意的是,在使用新的IntentsTestRule时要小心.在启动活动之前,它不会初始化Intents.init(),直到活动启动之后(afterActivityLaunched())." -无耻地插入我自己的帖子(中途向下有用的视觉效果)

我认为您遇到了一种竞争状况,在@Before方法中,您正在执行launchActivity(),然后espresso尝试在实际创建活动之前执行intending(not(isInternal())).respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null));,这意味着未调用afterActivityLaunched(),表示Intents.init()都不崩溃!

I think you are running into a race condition where in your @Before method you are executing launchActivity() then espresso tries to execute intending(not(isInternal())).respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null)); before your activity is actually created, which means afterActivityLaunched() isn't called, which means neither is Intents.init(), crash!

希望这会有所帮助.

这篇关于Android Espresso Intents测试随机失败,并显示``必须先调用init()才能使用此方法''的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆