Espresso-Intents

Espresso-Intents 是 Espresso 的扩展,它能够验证和存根被测应用程序发出的意图。它就像 Mockito,但适用于 Android 意图。

如果您的应用将功能委托给其他应用或平台,您可以使用 Espresso-Intents 专注于您自己的应用逻辑,同时假设其他应用或平台将正常运行。使用 Espresso-Intents,您可以匹配和验证您发出的意图,甚至可以提供存根响应来代替实际的意图响应。

在您的项目中包含 Espresso-Intents

在您的应用的app/build.gradle文件中,在dependencies内添加以下行

Groovy

androidTestImplementation 'androidx.test.espresso:espresso-intents:3.6.1'

Kotlin

androidTestImplementation('androidx.test.espresso:espresso-intents:3.6.1')

Espresso-Intents 仅与 Espresso 2.1+ 和 Android 测试库的 0.3+ 版本兼容,因此请确保您也更新了这些行

Groovy

androidTestImplementation 'androidx.test:runner:1.6.1'
androidTestImplementation 'androidx.test:rules:1.6.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'

Kotlin

androidTestImplementation('androidx.test:runner:1.6.1')
androidTestImplementation('androidx.test:rules:1.6.1')
androidTestImplementation('androidx.test.espresso:espresso-core:3.6.1')

编写测试规则

在编写 Espresso-Intents 测试之前,请设置一个IntentsTestRule。这是ActivityTestRule类的扩展,它使在功能性 UI 测试中轻松使用 Espresso-Intents API 成为可能。IntentsTestRule在每个用@Test注释的测试之前初始化 Espresso-Intents,并在每次测试运行后释放 Espresso-Intents。

以下代码片段是IntentsTestRule的示例

Kotlin

@get:Rule
val intentsTestRule = IntentsTestRule(MyActivity::class.java)

Java

@Rule
public IntentsTestRule<MyActivity> intentsTestRule =
    new IntentsTestRule<>(MyActivity.class);

匹配

Espresso-Intents 提供了根据某些匹配条件拦截传出意图的功能,这些条件使用 Hamcrest Matcher 定义。Hamcrest 允许您

  • 使用现有的意图匹配器:最简单的选项,几乎总是应该优先考虑。
  • 实现您自己的意图匹配器:最灵活的选项。更多详细信息可在Hamcrest 教程中名为“编写自定义匹配器”的部分找到。

Espresso-Intents 提供了intended()intending()方法分别用于意图验证和存根。两者都将 HamcrestMatcher<Intent>对象作为参数。

以下代码片段显示了意图验证,该验证使用现有的意图匹配器匹配启动浏览器的传出意图

Kotlin

assertThat(intent).hasAction(Intent.ACTION_VIEW)
assertThat(intent).categories().containsExactly(Intent.CATEGORY_BROWSABLE)
assertThat(intent).hasData(Uri.parse("www.google.com"))
assertThat(intent).extras().containsKey("key1")
assertThat(intent).extras().string("key1").isEqualTo("value1")
assertThat(intent).extras().containsKey("key2")
assertThat(intent).extras().string("key2").isEqualTo("value2")

Java

assertThat(intent).hasAction(Intent.ACTION_VIEW);
assertThat(intent).categories().containsExactly(Intent.CATEGORY_BROWSABLE);
assertThat(intent).hasData(Uri.parse("www.google.com"));
assertThat(intent).extras().containsKey("key1");
assertThat(intent).extras().string("key1").isEqualTo("value1");
assertThat(intent).extras().containsKey("key2");
assertThat(intent).extras().string("key2").isEqualTo("value2");

验证意图

Espresso-Intents 记录了尝试从被测应用程序启动活动的所有意图。使用intended()方法(类似于Mockito.verify()),您可以断言已看到给定的意图。但是,除非您明确配置它这样做,否则 Espresso-Intents 不会存根对意图的响应。

以下代码片段是一个示例测试,它验证但不存根对启动外部“电话”活动的传出意图的响应

Kotlin

@Test fun validateIntentSentToPackage() {
    // User action that results in an external "phone" activity being launched.
    user.clickOnView(system.getView(R.id.callButton))

    // Using a canned RecordedIntentMatcher to validate that an intent resolving
    // to the "phone" activity has been sent.
    intended(toPackage("com.android.phone"))
}

Java

@Test
public void validateIntentSentToPackage() {
    // User action that results in an external "phone" activity being launched.
    user.clickOnView(system.getView(R.id.callButton));

    // Using a canned RecordedIntentMatcher to validate that an intent resolving
    // to the "phone" activity has been sent.
    intended(toPackage("com.android.phone"));
}

存根

使用 intending() 方法(类似于 Mockito.when()),您可以为使用 startActivityForResult() 启动的活动提供存根响应。这对于外部活动特别有用,因为您无法操作外部活动的用户界面,也无法控制返回到测试活动下的 ActivityResult

以下代码片段实现了一个示例 activityResult_DisplaysContactsPhoneNumber() 测试,该测试验证当用户在被测应用中启动“联系人”活动时,是否会显示联系人电话号码。

  1. 构建在启动特定活动时要返回的结果。此示例测试拦截发送到“联系人”的所有 Intent,并使用结果代码 RESULT_OK,使用有效的 ActivityResult 来模拟它们的响应。

    Kotlin

    val resultData = Intent()
    val phoneNumber = "123-345-6789"
    resultData.putExtra("phone", phoneNumber)
    val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)

    Java

    Intent resultData = new Intent();
    String phoneNumber = "123-345-6789";
    resultData.putExtra("phone", phoneNumber);
    ActivityResult result =
        new ActivityResult(Activity.RESULT_OK, resultData);
  2. 指示 Espresso 在响应“联系人” intent 的所有调用时提供存根结果对象。

    Kotlin

    intending(toPackage("com.android.contacts")).respondWith(result)

    Java

    intending(toPackage("com.android.contacts")).respondWith(result);
  3. 验证用于启动活动的动作是否产生了预期的存根结果。在本例中,示例测试检查在启动“联系人活动”时是否返回并显示电话号码 "123-345-6789"

    Kotlin

    onView(withId(R.id.pickButton)).perform(click())
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)))

    Java

    onView(withId(R.id.pickButton)).perform(click());
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)));

以下是完整的 activityResult_DisplaysContactsPhoneNumber() 测试。

Kotlin

@Test fun activityResult_DisplaysContactsPhoneNumber() {
    // Build the result to return when the activity is launched.
    val resultData = Intent()
    val phoneNumber = "123-345-6789"
    resultData.putExtra("phone", phoneNumber)
    val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)

    // Set up result stubbing when an intent sent to "contacts" is seen.
    intending(toPackage("com.android.contacts")).respondWith(result)

    // User action that results in "contacts" activity being launched.
    // Launching activity expects phoneNumber to be returned and displayed.
    onView(withId(R.id.pickButton)).perform(click())

    // Assert that the data we set up above is shown.
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)))
}

Java

@Test
public void activityResult_DisplaysContactsPhoneNumber() {
    // Build the result to return when the activity is launched.
    Intent resultData = new Intent();
    String phoneNumber = "123-345-6789";
    resultData.putExtra("phone", phoneNumber);
    ActivityResult result =
        new ActivityResult(Activity.RESULT_OK, resultData);

    // Set up result stubbing when an intent sent to "contacts" is seen.
    intending(toPackage("com.android.contacts")).respondWith(result);

    // User action that results in "contacts" activity being launched.
    // Launching activity expects phoneNumber to be returned and displayed.
    onView(withId(R.id.pickButton)).perform(click());

    // Assert that the data we set up above is shown.
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)));
}

其他资源

有关在 Android 测试中使用 Espresso-Intents 的更多信息,请参阅以下资源。

示例