[英]How to check expected intent sent without actually launching activity in Espresso?
I have a UI test which clicks a button, and then launch a new Activity in its onClickListener. 我有一个UI测试点击按钮,然后在其onClickListener中启动一个新的Activity。 The test checks whether expected intent is sent or not. 该测试检查是否发送了预期意图。
My problem is, I want to test whether expected intent is sent without actually launching the activity . 我的问题是,我想测试是否在没有实际启动活动的情况下发送预期意图。 Because I found that new activity initializes its state, and it makes subsequent tests flaky. 因为我发现新活动初始化了它的状态,并且后续测试变得不稳定。
I know there are two Espresso Intents api, which are intended
and intending
, but both fail to meet my needs. 我知道有两种Espresso Intents api,它们都是intended
和intending
,但都无法满足我的需求。 intended
api actually launches the target activity, and intending
api doesn't launch the activity, but it calls onActivityResult
callback which I don't want either. intended
api实际上启动目标活动,并且intending
api不启动活动,但它调用onActivityResult
回调,我也不想要。 Because I'm afraid that code inside onActivityResult
may cause another flakiness. 因为我担心onActivityResult
中的代码可能会导致另一个瑕疵。 Also intending
doesn't assert whether matching intent is sent, it just calls onActivityResult
callback when matching intent is found, which means I have to check whether onActivityResult
is called or not! 同时intending
言是否发送匹配意图,它只是在找到匹配意图时调用onActivityResult
回调,这意味着我必须检查onActivityResult
是否被调用!
Is there any clean way to achieve what I want? 有没有什么干净的方法来实现我想要的?
If you want to test whether expected intent is sent without actually launching the activity you can do it by capturing the intent with an activityResult and then catching the activity : 如果要测试是否在未实际启动活动的情况下发送预期意图,可以通过使用activityResult捕获意图然后捕获活动来执行此操作:
Intent intent = new Intent();
ActivityResult intentResult = new ActivityResult(Activity.RESULT_OK,intent);
intending(anyIntent()).respondWith(intentResult);
onView(withId(R.id.view_id_to_perform_clicking)).check(matches(isDisplayed())).perform(click());
intended(allOf(hasComponent(ActivityToBeOpened.class.getName())));
This would catch any attempt of launching ActivityToBeOpened. 这将捕获任何启动ActivityToBeOpened的尝试。 If you want to be more specific you can also catch an intent with Extras: 如果您想要更具体,您还可以使用Extras捕获意图:
intended(allOf(hasComponent(ActivityToBeOpened.class.getName()), hasExtra("paramName", "value")));
Hope that helps. 希望有所帮助。
Espresso's Intents
class is a concise and handy api, but when it doesn't meet your needs, there is an alternative. Espresso的Intents
课程简洁而方便,但如果它不能满足您的需求,还有另一种选择。 If you use AndroidJUnit4
test runner, you can get Instrumentaion
instance using InstrumentationRegistry.getInstrumentation()
, and then you can add Instrumentation.ActivityMonitor
instance. 如果使用AndroidJUnit4
测试运行器,则可以使用InstrumentationRegistry.getInstrumentation()
获取Instrumentaion
实例,然后可以添加Instrumentation.ActivityMonitor
实例。
Instrumentation.ActivityMonitor am = new Instrumentation.ActivityMonitor("YOUR_ACTIVITY", null, true);
InstrumentationRegistry.getInstrumentation().addMonitor(am);
onView(withId(R.id.view_id_to_perform_clicking)).check(matches(isDisplayed())).perform(click());
assertTrue(InstrumentationRegistry.getInstrumentation().checkMonitorHit(am, 1));
The third parameter of ActivityMonitor
constructor tells we want to block activity launching. ActivityMonitor
构造函数的第三个参数告诉我们要阻止活动启动。 Note that this approach has its limitation. 请注意,这种方法有其局限性。 In contrast to Espresso Intents' rich Matcher support , You can not set multiple condition for ActivityMonitor
. 与Espresso Intents 丰富的Matcher支持相比 ,您无法为ActivityMonitor
设置多个条件。
You can find several samples in ApiDemos , especially in ContactsSelectInstrumentation
class. 您可以在ApiDemos中找到几个示例,尤其是在ContactsSelectInstrumentation
类中。
Actually, you can block any intent to launch an external or your own activity but still use the rich Espresso Intents API: 实际上,您可以阻止任何启动外部或您自己活动的意图,但仍然使用丰富的Espresso Intents API:
Instrumentation.ActivityMonitor soloMonitor = solo.getActivityMonitor();
instrumentation.removeMonitor(soloMonitor);
IntentFilter filter = null;
// Block any intent
Instrumentation.ActivityMonitor monitor = instrumentation.addMonitor(filter, null, true);
instrumentation.addMonitor(soloMonitor);
// User action that results in an external browser activity being launched.
user.clickOnView(system.getView(R.id.callButton));
instrumentation.waitForIdleSync();
Intents.intended(Matchers.allOf(
IntentMatchers.hasAction(Matchers.equalTo(Intent.ACTION_VIEW)),
IntentMatchers.hasData(Matchers.equalTo(Uri.parse(url))),
IntentMatchers.toPackage(chromePackage)));
instrumentation.removeMonitor(monitor);
You able to do that because Espresso Intents still records every Intent with IntentMonitor callback even if you block them. 你能够做到这一点,因为即使你阻止它们,Espresso Intents仍然会记录每个Intent和IntentMonitor回调。 Look at the source code of Espresso Intents on how they do that. 查看Espresso Intents的源代码,了解他们如何做到这一点。
If you use Robotium Solo framework you need to move your own ActivityMonitor
before their one. 如果您使用Robotium Solo框架,则需要在自己的ActivityMonitor
之前移动它。 Otherwise just skip the lines related to this. 否则只需跳过与此相关的行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.