Espresso-Web 是处理 Android WebView 界面组件的入口点。Espresso-Web 重复使用了热门 WebDriver API 中的 Atom,以检查和控制 WebView 的行为。
何时使用 Espresso-Web
使用 Espresso-Web 测试您的混合应用,特别是测试应用的原生界面组件与其 WebView
界面组件的集成情况。您可以将 Espresso-Web API 与其他 Espresso API 结合使用,以完全与 WebView
对象内的网页元素进行互动。
如果您只需要测试 WebView
本身,而不是测试 WebView
与应用中原生组件之间的互动,可以考虑使用 WebDriver 等框架来编写通用网页测试。如果您使用网页测试框架,则无需使用 Android 设备或 Java 虚拟机,这会使您的测试运行得更快、更可靠。话虽如此,Espresso-Web 允许您重复使用自定义 WebDriver Atom,这为您提供了很大的灵活性,尤其是在编写计划针对独立网页应用和包含 Android 界面应用运行的测试时。
工作原理
与 Espresso 的 onData()
方法类似,WebView
互动包含多个 Atom。WebView
互动使用 Java 编程语言和 JavaScript 桥的组合来完成其工作。由于公开来自 JavaScript 环境的数据不会引入竞态条件(Espresso 在基于 Java 的一侧看到的一切都是独立的副本),因此完全支持从 Web.WebInteraction
对象返回数据,从而允许您验证从请求返回的所有数据。
什么是 WebDriver Atom?
WebDriver 框架使用 Atom 以编程方式查找和操作网页元素。WebDriver 使用 Atom 来进行浏览器操作。从概念上讲,Atom 类似于 ViewAction
,它是一个独立的单元,可在您的界面中执行操作。您可以使用一组定义的方法(例如 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
。 在 dependencies 中添加以下行
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 用法
使用 Espresso 在 Android 上处理 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。
您可以通过在被测 activity 中调用 forceJavascriptEnabled()
来强制启用 JavaScript,如以下代码段所示。
@RunWith(AndroidJUnit4::class) class MyTestSuite { @get:Rule val activityScenarioRule = activityScenarioRule<MyWebViewActivity>() @Test fun testWebViewInteraction() { onWebView().forceJavascriptEnabled() } }
常见的网页互动
与 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
对象互动。