如何在 Espresso 中实际启动 activity 的情况下检查发送的预期意图?
How can I check the expected intent sent without actually launching activity in Espresso?
我有一个 UI 测试,它单击一个按钮,然后在其 onClickListener 中启动一个新的 Activity。该测试检查是否发送了预期的意图。
我的问题是,我想测试是否发送了预期的意图 而没有实际启动 activity。因为我发现 new activity 初始化了它的状态,它使后续测试不稳定。
我知道有两个Espresso Intents API, which are <a href="https://developer.android.com/reference/android/support/test/espresso/intent/Intents.html#intended(org.hamcrest.Matcher%3Candroid.content.Intent%3E)" rel="nofollow noreferrer">intended</a>
and <a href="https://developer.android.com/reference/android/support/test/espresso/intent/Intents.html#intending(org.hamcrest.Matcher%3Candroid.content.Intent%3E)" rel="nofollow noreferrer">intending</a>
,但是都不能满足我的需求。 intended
API 实际上启动目标 activity,而 intending
API 不启动 activity,但它调用 onActivityResult
我也不想要的回调。因为我担心 onActivityResult
中的代码可能会导致另一个漏洞。
另外intending
不断言是否发送了匹配的意图。它只是在找到匹配意图时调用 onActivityResult
回调,这意味着我必须检查是否调用了 onActivityResult
!
有没有一种干净的方法来实现我想要的?
Espresso 的 Intents
class 简洁好用 api,但当它不能满足您的需求时,还有一个替代方案。如果你使用AndroidJUnit4
测试运行器,你可以获得<a href="https://developer.android.com/reference/android/app/Instrumentation.html" rel="nofollow">Instrumentaion</a>
instance using <a href="https://developer.android.com/reference/android/support/test/InstrumentationRegistry.html#getInstrumentation()" rel="nofollow">InstrumentationRegistry.getInstrumentation()</a>
, and then you can add <a href="https://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html" rel="nofollow">Instrumentation.ActivityMonitor</a>
实例。
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));
ActivityMonitor
构造函数的第三个参数告诉我们要阻止 activity 启动。请注意,这种方法有其局限性。与 Espresso Intents 的 rich Matcher support 相比,您不能为 ActivityMonitor
.
设置多个条件
您可以在 ApiDemos, especially in <a href="https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/app/ContactsSelectInstrumentation.java" rel="nofollow">ContactsSelectInstrumentation</a>
class 中找到多个示例。
如果您想测试预期的意图是否在没有实际启动 activity 的情况下发送,您可以通过使用 activityResult 捕获意图然后捕获 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())));
这会捕获任何启动 ActivityToBeOpened 的尝试。如果您想更具体一些,您还可以使用 Extras 捕捉意图:
intended(allOf(hasComponent(ActivityToBeOpened.class.getName()), hasExtra("paramName", "value")));
希望对您有所帮助。
实际上,您可以阻止任何启动外部或您自己的 Intent activity,但仍然使用丰富的 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);
你能够做到这一点,因为 Espresso Intents 仍然记录每个 Intent IntentMonitor callback even if you block them. Look at the source code of Espresso Intents 他们是如何做到的。
如果您使用 Robotium Solo 框架,您需要将自己的 ActivityMonitor
移到他们的框架之前。否则就跳过与此相关的行。
我有一个 UI 测试,它单击一个按钮,然后在其 onClickListener 中启动一个新的 Activity。该测试检查是否发送了预期的意图。
我的问题是,我想测试是否发送了预期的意图 而没有实际启动 activity。因为我发现 new activity 初始化了它的状态,它使后续测试不稳定。
我知道有两个Espresso Intents API, which are <a href="https://developer.android.com/reference/android/support/test/espresso/intent/Intents.html#intended(org.hamcrest.Matcher%3Candroid.content.Intent%3E)" rel="nofollow noreferrer">intended</a>
and <a href="https://developer.android.com/reference/android/support/test/espresso/intent/Intents.html#intending(org.hamcrest.Matcher%3Candroid.content.Intent%3E)" rel="nofollow noreferrer">intending</a>
,但是都不能满足我的需求。 intended
API 实际上启动目标 activity,而 intending
API 不启动 activity,但它调用 onActivityResult
我也不想要的回调。因为我担心 onActivityResult
中的代码可能会导致另一个漏洞。
另外intending
不断言是否发送了匹配的意图。它只是在找到匹配意图时调用 onActivityResult
回调,这意味着我必须检查是否调用了 onActivityResult
!
有没有一种干净的方法来实现我想要的?
Espresso 的 Intents
class 简洁好用 api,但当它不能满足您的需求时,还有一个替代方案。如果你使用AndroidJUnit4
测试运行器,你可以获得<a href="https://developer.android.com/reference/android/app/Instrumentation.html" rel="nofollow">Instrumentaion</a>
instance using <a href="https://developer.android.com/reference/android/support/test/InstrumentationRegistry.html#getInstrumentation()" rel="nofollow">InstrumentationRegistry.getInstrumentation()</a>
, and then you can add <a href="https://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html" rel="nofollow">Instrumentation.ActivityMonitor</a>
实例。
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));
ActivityMonitor
构造函数的第三个参数告诉我们要阻止 activity 启动。请注意,这种方法有其局限性。与 Espresso Intents 的 rich Matcher support 相比,您不能为 ActivityMonitor
.
您可以在 ApiDemos, especially in <a href="https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/app/ContactsSelectInstrumentation.java" rel="nofollow">ContactsSelectInstrumentation</a>
class 中找到多个示例。
如果您想测试预期的意图是否在没有实际启动 activity 的情况下发送,您可以通过使用 activityResult 捕获意图然后捕获 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())));
这会捕获任何启动 ActivityToBeOpened 的尝试。如果您想更具体一些,您还可以使用 Extras 捕捉意图:
intended(allOf(hasComponent(ActivityToBeOpened.class.getName()), hasExtra("paramName", "value")));
希望对您有所帮助。
实际上,您可以阻止任何启动外部或您自己的 Intent activity,但仍然使用丰富的 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);
你能够做到这一点,因为 Espresso Intents 仍然记录每个 Intent IntentMonitor callback even if you block them. Look at the source code of Espresso Intents 他们是如何做到的。
如果您使用 Robotium Solo 框架,您需要将自己的 ActivityMonitor
移到他们的框架之前。否则就跳过与此相关的行。