Android Espresso Intents测试随机失败,并显示``必须先调用init()才能使用此方法'' [英] Android Espresso Intents test randomly fail with ``init() must be called prior to using this method``
问题描述
我正在努力将一个项目推入浓缩咖啡测试.我已经阅读了一堆文件,并按照给定的方法开始使用.
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!
推荐答案
两种解决方案:
- 使用ActivityTestRule代替IntentsTestRule,然后分别在@Before和@After中手动调用Intents.init()和Intents.release().
- 编写一个自定义的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屋!