Espresso-Web 是用于处理 Android WebView UI 组件的入口点。Espresso-Web 重用来自流行的 WebDriver API 的 Atom 来检查和控制 WebView 的行为。
何时使用 Espresso-Web
使用 Espresso-Web 测试您的混合应用,尤其是应用的原生 UI 组件与其 WebView
UI 组件的集成。您可以将 Espresso-Web API 与其他 Espresso API 结合使用,以完全与 WebView
对象内的 Web 元素进行交互。
如果您只需要测试 WebView
本身,而不是测试 WebView
与应用中原生组件之间的交互,请考虑使用像 WebDriver 这样的框架编写通用 Web 测试。如果您使用 Web 测试框架,则无需使用 Android 设备或 Java 虚拟机,这使得您的测试运行得更快、更可靠。也就是说,Espresso-Web 允许您重用自定义 WebDriver atom,这为您提供了很大的灵活性,尤其是在编写计划针对独立 Web 应用和包含 Android UI 的应用运行的测试时。
工作原理
与 Espresso 的 onData()
方法类似,WebView
交互包含多个 Atom。 WebView
交互使用 Java 编程语言和 JavaScript 桥的组合来完成其工作。由于通过公开来自 JavaScript 环境的数据没有引入竞争条件的机会——Espresso 在基于 Java 的一侧看到的所有内容都是一个隔离的副本——因此完全支持从 Web.WebInteraction
对象返回数据,允许您验证从请求返回的所有数据。
什么是 WebDriver Atom?
WebDriver 框架使用 Atom 以编程方式查找和操作 Web 元素。Atom 用于 WebDriver 以允许浏览器操作。从概念上讲,Atom 类似于 ViewAction
,一个执行 UI 操作的自包含单元。您可以通过定义的方法列表(例如 findElement()
和 getElement()
)公开 Atom,以从用户的角度驱动浏览器。但是,如果您直接使用 WebDriver 框架,则需要正确地编排 Atom,这需要相当冗长的逻辑。
在 Espresso 中,类 Web
和 Web.WebInteraction
封装了此样板代码,并为与 WebView 对象交互提供了类似 Espresso 的体验。因此,在 WebView
的上下文中,Atom 用作传统 Espresso ViewMatchers
和 ViewActions
的替代。
然后,API 看起来非常简单
Kotlin
onWebView() .withElement(Atom) .perform(Atom) .check(WebAssertion)
Java
onWebView() .withElement(Atom) .perform(Atom) .check(WebAssertion);
要了解更多信息,请阅读 Selenium 关于 Atom 的文档。
实现 WebView
请按照以下部分中显示的指南,在应用的测试中使用 WebView
。
包
要将 Espresso-Web 包含到您的项目中,请完成以下步骤
- 打开应用的
build.gradle
文件。这通常不是顶层的build.gradle
文件,而是app/build.gradle
文件。 在依赖项内部添加以下行
Groovy
androidTestImplementation 'androidx.test.espresso:espresso-web:3.6.1'
Kotlin
androidTestImplementation('androidx.test.espresso:espresso-web:3.6.1')
Espresso-Web 仅与 Espresso 2.2 或更高版本以及测试库的 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')
常用 API 用法
在 Android 上使用 Espresso 与 WebView 交互时,onWebView()
方法是主要入口点。您可以使用此方法执行 Espresso-Web 测试,例如以下操作
Kotlin
onWebView() .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...)) .perform(webClick()) // Similar to perform(click()) // Similar to check(matches(...)) .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")))
Java
onWebView() .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...)) .perform(webClick()) // Similar to perform(click()) // Similar to check(matches(...)) .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")));
在此示例中,Espresso-Web 查找 ID 为 "link_2"
的 DOM 元素并单击它。然后,该工具验证 WebView 是否发送包含 "navigation_2.html"
字符串的 GET 请求。
JavaScript 支持
执行测试时,系统使用 JavaScript 执行所有 WebView 交互。因此,为了支持 JavaScript 评估,被测 WebView 必须启用 JavaScript。
您可以通过调用 forceJavascriptEnabled()
作为 被测活动中的操作 来强制启用 JavaScript,如下面的代码片段所示。
@RunWith(AndroidJUnit4::class) class MyTestSuite { @get:Rule val activityScenarioRule = activityScenarioRule<MyWebViewActivity>() @Test fun testWebViewInteraction() { onWebView().forceJavascriptEnabled() } }
常见的 Web 交互
与 Web.WebInteraction
对象的常见交互包括以下内容
-
withElement()
引用 WebView 中的 DOM 元素。示例
Kotlin
onWebView().withElement(findElement(Locator.ID, "teacher"))
Java
onWebView().withElement(findElement(Locator.ID, "teacher"));
-
withContextualElement()
引用 WebView 中相对于另一个 DOM 元素的范围 DOM 元素。您应该首先调用withElement()
来建立Web.WebInteraction
对象(DOM 元素)的引用。示例
Kotlin
.withElement(findElement(Locator.ID, "teacher")) .withContextualElement(findElement(Locator.ID, "person_name"))
Java
.withElement(findElement(Locator.ID, "teacher")) .withContextualElement(findElement(Locator.ID, "person_name"));
-
check()
评估条件,确保其解析为true
。示例
Kotlin
onWebView() .withElement(findElement(Locator.ID, "teacher")) .withContextualElement(findElement(Locator.ID, "person_name")) .check(webMatches(getText(), containsString("Socrates")))
Java
onWebView() .withElement(findElement(Locator.ID, "teacher")) .withContextualElement(findElement(Locator.ID, "person_name")) .check(webMatches(getText(), containsString("Socrates")));
-
perform()
在 WebView 中执行操作,例如单击元素。示例
Kotlin
onWebView() .withElement(findElement(Locator.ID, "teacher")) .perform(webClick())
Java
onWebView() .withElement(findElement(Locator.ID, "teacher")) .perform(webClick());
-
reset()
将 WebView 恢复到其初始状态。当先前的操作(例如单击)导致导航更改,从而使 ElementReference 和 WindowReference 对象无法访问时,这很有必要。注意:虽然在对多页工作流(例如表单提交)进行断言时使用
reset()
很有用,但您的测试通常应范围有限,并专注于单个页面。示例
Kotlin
onWebView() .withElement(...) .perform(...) .reset()
Java
onWebView() .withElement(...) .perform(...) .reset();
示例
以下示例测试是否在将文本输入 WebView 并选择“提交”按钮后,相同的文本会出现在同一 WebView 中的不同元素中。
Kotlin
const val MACCHIATO = "Macchiato" @RunWith(AndroidJUnit4::class) class MyEspressoWebTestSuite { @Test fun typeTextInInput_clickButton_SubmitsForm() { // Create an intent that displays a web form. val webFormIntent = Intent() // ... // Lazily launch the Activity with a custom start Intent per test. ActivityScenario.launchActivity(webFormIntent) // Selects the WebView in your layout. If you have multiple WebView // objects, you can also use a matcher to select a given WebView, // onWebView(withId(R.id.web_view)). onWebView() // Find the input element by ID. .withElement(findElement(Locator.ID, "text_input")) // Clear previous input and enter new text into the input element. .perform(clearElement()) .perform(DriverAtoms.webKeys(MACCHIATO)) // Find the "Submit" button and simulate a click using JavaScript. .withElement(findElement(Locator.ID, "submitBtn")) .perform(webClick()) // Find the response element by ID, and verify that it contains the // entered text. .withElement(findElement(Locator.ID, "response")) .check(webMatches(getText(), containsString(MACCHIATO))) } }
Java
public static final String MACCHIATO = "Macchiato"; @Test public void typeTextInInput_clickButton_SubmitsForm() { // Create an intent that displays a web form. Intent webFormIntent = new Intent(); // ... // Lazily launch the Activity with a custom start Intent per test. ActivityScenario.launchActivity(webFormIntent); // Selects the WebView in your layout. If you have multiple WebView objects, // you can also use a matcher to select a given WebView, // onWebView(withId(R.id.web_view)). onWebView() // Find the input element by ID. .withElement(findElement(Locator.ID, "text_input")) // Clear previous input and enter new text into the input element. .perform(clearElement()) .perform(DriverAtoms.webKeys(MACCHIATO)) // Find the "Submit" button and simulate a click using JavaScript. .withElement(findElement(Locator.ID, "submitBtn")) .perform(webClick()) // Find the response element by ID, and verify that it contains the // entered text. .withElement(findElement(Locator.ID, "response")) .check(webMatches(getText(), containsString(MACCHIATO))); }
其他资源
有关在 Android 测试中使用 Espresso-Web 的更多信息,请参阅以下资源。
示例
- WebBasicSample:使用 Espresso-Web 与
WebView
对象交互。