How to check expected intent sent without actually launching activity in Espresso?

前端 未结 3 1507
佛祖请我去吃肉
佛祖请我去吃肉 2021-02-14 01:42

I have a UI test which clicks a button, and then launch a new Activity in its onClickListener. The test checks whether expected intent is sent or not.

My problem is, I w

相关标签:
3条回答
  • 2021-02-14 01:59

    Espresso's Intents class is a concise and handy api, but when it doesn't meet your needs, there is an alternative. If you use AndroidJUnit4 test runner, you can get Instrumentaion instance using InstrumentationRegistry.getInstrumentation(), and then you can add Instrumentation.ActivityMonitor instance.

    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. Note that this approach has its limitation. In contrast to Espresso Intents' rich Matcher support, You can not set multiple condition for ActivityMonitor.

    You can find several samples in ApiDemos, especially in ContactsSelectInstrumentation class.

    0 讨论(0)
  • 2021-02-14 02:11

    Actually, you can block any intent to launch an external or your own activity but still use the rich 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. Look at the source code of Espresso Intents on how they do that.

    If you use Robotium Solo framework you need to move your own ActivityMonitor before their one. Otherwise just skip the lines related to this.

    0 讨论(0)
  • 2021-02-14 02:13

    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 :

    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. If you want to be more specific you can also catch an intent with Extras:

    intended(allOf(hasComponent(ActivityToBeOpened.class.getName()), hasExtra("paramName", "value")));
    

    Hope that helps.

    0 讨论(0)
提交回复
热议问题