简体   繁体   English

如何检查发送的预期意图而不是在Espresso中实际启动活动?

[英]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,它们都是intendedintending ,但都无法满足我的需求。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM