在单个应用程序中测试用户交互有助于确保用户在与应用程序进行交互时不会遇到意外的结果, 或遇到糟糕的体验. 如果需要验证应用的 UI 功能是否正常, 则应该养成创建用户界面 (UI) 测试的习惯.
Espresso 测试框架, 由 Android 测试支持库提供, 用于编写 UI 测试的 API 来模拟单个应用程序内的用户交互. Espresso 测试可以在运行 Android 2.3.3(API 等级 10)及更高版本的设备上运行. 使用 Espresso 的一个关键好处是, 它提供了测试操作与正在测试的应用程序的用户界面的自动同步. Espresso 检测主线程是否处于空闲状态, 以便能够在适当的时候运行测试命令, 从而提高测试的可靠性. 此功能还可以减轻在测试代码中添加任何计时变通方法如 Thread.sleep() 的麻烦.
Espresso 测试框架基于 instrumentation 的 API, 并通过 AndroidJUnitRunner 运行测试.
设置 Espresso
在使用 Espresso 构建 UI 测试之前, 请确保配置测试源代码位置和项目依赖关系, 如 "Getting Started with Testing http://www.testclass.net/android/fundamentals/" 中所述.
在 Android 应用程序模块的 build.gradle 文件中, 必须设置对 Espresso 库的依赖关系引用:
- dependencies {
- // Other dependencies ...
- androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
- }
关闭测试设备上的动画 - 在测试设备中打开系统动画可能会导致意外的结果, 或者可能导致测试失败. 通过打开 "开发人员" 选项关闭 "设置" 中的动画, 并关闭以下所有选项:
窗口动画比例
过渡动画比例
动画师持续时间比例
如果你希望将项目设置为使用核心 API 提供的 Espresso 功能以外的功能, 请参阅此资源 https://developer.android.com/training/testing/espresso/index.html
创建一个 Espresso 测试
要创建 Espresso 测试, 请创建遵循此编程模型的 Java 类:
1. 找到想要在活动中测试的 UI 组件 (例如, 应用程序中的登录按钮), 调用 onView() 方法, 或者调用 AdapterView 控件的 onData()方法.
2. 通过调用 ViewInteraction.perform()或 DataInteraction.perform()方法并传入用户操作(例如, 单击登录按钮), 模拟特定的用户交互以在该 UI 组件上执行. 要在同一 UI 组件上对多个操作进行排序, 请使用方法参数中的逗号分隔列表链接它们.
3. 根据需要重复上述步骤, 模拟目标应用中多个活动的用户操作.
4. 在执行这些用户交互之后, 使用 ViewAssertions 方法来检查 UI 是否反映了期望的状态或行为.
以下各节将详细介绍这些步骤.
下面的代码片段显示了你的测试类可能如何调用这个基本的工作流程:
- onView(withId(R.id.my_view)) // withId(R.id.my_view) is a ViewMatcher
- .perform(click()) // click() is a ViewAction
- .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
使用 Espresso 和 ActivityTestRule
以下部分介绍如何使用 JUnit 4 样式创建新的 Espresso 测试, 并使用 ActivityTestRule 来减少需要编写的样板代码的数量. 通过使用 ActivityTestRule, 测试框架在每个使用 @Test 注释的测试方法之前以及在使用 @Before 注释的方法之前启动被测活动. 测试完成后, 框架处理关闭活动, 所有使用 @After 注释的方法都会运行.
- package com.example.android.testing.espresso.BasicSample;
- import org.junit.Before;
- import org.junit.Rule;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import android.support.test.rule.ActivityTestRule;
- import android.support.test.runner.AndroidJUnit4;
- ...
- @RunWith(AndroidJUnit4.class)
- @LargeTest
- public class ChangeTextBehaviorTest {
- private String mStringToBetyped;
- @Rule
- public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
- MainActivity.class);
- @Before
- public void initValidString() {
- // Specify a valid string.
- mStringToBetyped = "Espresso";
- }
- @Test
- public void changeText_sameActivity() {
- // Type text and then press the button.
- onView(withId(R.id.editTextUserInput))
- .perform(typeText(mStringToBetyped), closeSoftKeyboard());
- onView(withId(R.id.changeTextBt)).perform(click());
- // Check that the text was changed.
- onView(withId(R.id.textToBeChanged))
- .check(matches(withText(mStringToBetyped)));
- }
- }
访问 UI 组建
在 Espresso 可以与被测试的应用程序进行交互之前, 必须先指定 UI 组件或视图. Espresso 支持使用 Hamcrest 匹配器 http://hamcrest.org/ 在应用程序中指定视图和适配器.
要查找视图, 请调用 onView()方法并传递一个视图匹配器, 该视图匹配器指定要定位的视图. 这在指定视图匹配器中有更详细的描述. onView()方法返回 ViewInteraction 对象, 允许测试与视图进行交互. 但是, 如果要在 RecyclerView 布局中查找视图, 则调用 onView()方法可能不起作用. 在这种情况下, 请按照在 AdapterView 中查找视图中的说明进行操作.
注意: onView()方法不检查你指定的视图是否有效. 相反, Espresso 只搜索当前的视图层次结构, 使用 matcher 提供的视图. 如果没有找到匹配, 该方法将抛出一个 NoMatchingViewException.
下面的代码片段展示了如何编写一个测试来访问 EditText 字段, 输入一个文本字符串, 关闭虚拟键盘, 然后执行按钮单击.
- public void testChangeText_sameActivity() {
- // Type text and then press the button.
- onView(withId(R.id.editTextUserInput))
- .perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard());
- onView(withId(R.id.changeTextButton)).perform(click());
- // Check that the text was changed.
- ...
- }
指定一个视图匹配器
您可以使用以下方法指定视图匹配器:
在 ViewMatchers 类中调用方法. 例如, 要查找显示的文本字符串来查找视图, 可以调用如下所示的方法:
onView(withText("Sign-in"));
也可以调用 withId()并提供视图的资源 ID(R.id), 如下例所示:
onView(withId(R.id.button_signin));
Android 资源 ID 不保证是唯一的. 如果测试尝试匹配多个视图使用的资源 ID, 则 Espresso 会引发 AmbiguousViewMatcherException.
使用 Hamcrest http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html 类. 可以使用 AllOf()方法来组合多个匹配器, 例如
containsString()
和 instanceOf(). 这种方法允许更窄地过滤匹配结果, 如以下示例所示:
onView(allOf(withId(R.id.button_signin), withText("Sign-in")));
但是, 不能使用关键字来筛选不匹配匹配器的视图, 如以下示例所示:
onView(allOf(withId(R.id.button_signin), not(withText("Sign-out"))));
要在测试中使用这些方法, 请导入
org.hamcrest.Matchers
包. 要了解有关 Hamcrest 匹配的更多信息, 请参阅 Hamcrest 网站
要改善 Espresso 测试的性能, 请指定查找目标视图所需的最低匹配信息. 例如, 如果某个视图可以通过其描述性文本唯一标识, 则不需要指定它也可以从 TextView 实例分配.
在 AdapterView 中查找视图
在 AdapterView 小部件中, 视图在运行时动态填充子视图. 如果要测试的目标视图位于 AdapterView 中 (如 ListView,GridView 或 Spinner), 则 onView() 方法可能无法正常工作, 因为只有视图的子集可能会加载到当前视图层次结构中.
相反, 调用 onData()方法来获取 DataInteraction 对象来访问目标视图元素. Espresso 将目标视图元素加载到当前视图层次结构中. Espresso 还负责滚动目标元素, 并将元素放在焦点上.
注意: onData()方法不会检查你指定的项目是否与视图对应. Espresso 只搜索当前的视图层次结构. 如果找不到匹配, 则该方法将引发 NoMatchingViewException.
以下代码片段显示了如何使用 onData()方法和 Hamcrest 匹配一起搜索包含给定字符串的列表中的特定行. 在此示例中, LongListActivity 类包含通过 SimpleAdapter 公开的字符串列表.
- onData(allOf(is(instanceOf(Map.class)),
- hasEntry(equalTo(LongListActivity.ROW_TEXT), is("test input")));
执行操作
调用
ViewInteraction.perform()
或
DataInteraction.perform()
方法来模拟 UI 组件上的用户交互. 您必须传入一个或多个 ViewAction 对象作为参数. Espresso 根据给定的顺序依次触发每个动作, 并在主线程中执行它们.
ViewActions 类提供了用于指定常用操作的帮助程序方法列表. 可以使用这些方法作为方便的快捷方式, 而不是创建和配置单独的 ViewAction 对象. 你可以指定如下操作:
ViewActions.click(): 点击视图.
ViewActions.typeText(): 点击一个视图并输入一个指定的字符串.
ViewActions.scrollTo(): 滚动到视图. 目标视图必须从 ScrollView 继承, 其 android:visibility 属性的值必须是可见的. 对于扩展 AdapterView 的视图 (例如, ListView),onData() 方法负责为您滚动.
ViewActions.pressKey(): 使用指定的键码进行按键操作.
ViewActions.clearText(): 清除目标视图中的文本.
如果目标视图位于 ScrollView 的内部, 则先执行
ViewActions.scrollTo()
操作, 然后再执行其他操作. 如果已经显示视图, 则
ViewActions.scrollTo()
操作将不起作用.
用 Espresso Intents 隔离测试你的活动
Espresso Intents 可以验证应用程序发送的意图的验证和存根. 通过 Espresso Intents, 可以通过拦截传出的意图, 对结果进行存根并将其发送回被测组件来隔离测试应用程序, 活动或服务.
- dependencies {
- // Other dependencies ...
- androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
- }
为了测试一个 intent, 你需要创建一个 IntentsTestRule 类的实例, 它与 ActivityTestRule 类非常相似. IntentsTestRule 类在每次测试之前初始化 Espresso Intents, 终止主活动, 并在每次测试后释放 Espresso Intents.
以下代码片段中显示的测试类为明确的意图提供了一个简单的测试. 它测试建立你的第一个应用程序教程中创建的活动和意图.
- @Large
- @RunWith(AndroidJUnit4.class)
- public class SimpleIntentTest {
- private static final String MESSAGE = "This is a test";
- private static final String PACKAGE_NAME = "com.example.myfirstapp";
- /* Instantiate an IntentsTestRule object. */
- @Rule
- public IntentsTestRule?MainActivity> mIntentsRule =
- new IntentsTestRule?>(MainActivity.class);
- @Test
- public void verifyMessageSentToMessageActivity() {
- // Types a message into a EditText element.
- onView(withId(R.id.edit_message))
- .perform(typeText(MESSAGE), closeSoftKeyboard());
- // Clicks a button to send the message to another
- // activity through an explicit intent.
- onView(withId(R.id.send_message)).perform(click());
- // Verifies that the DisplayMessageActivity received an intent
- // with the correct package name and message.
- intended(allOf(
- hasComponent(hasShortClassName(".DisplayMessageActivity")),
- toPackage(PACKAGE_NAME),
- hasExtra(MainActivity.EXTRA_MESSAGE, MESSAGE)));
- }
- }
有关 Espresso Intents 的更多信息, 请参阅 Android 测试支持库网站上的 Espresso Intent 文档. 您还可以下载 IntentsBasicSample 和 IntentsAdvancedSample 代码示例.
用 Espresso web 测试 WebViews
Espresso Web 允许测试活动中包含的 WebView 组件. 它使用 WebDriver API 来检查和控制 WebView 的行为.
要开始使用 Espresso Web 进行测试, 需要将以下行添加到应用程序的 build.gradle 文件中:
- dependencies {
- // Other dependencies ...
- androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2.2'
- }
使用 Espresso Web 创建测试时, 需要在实例化 ActivityTestRule 对象以测试活动时在 WebView 上启用 JavaScript. 在测试中, 可以选择显示在 WebView 中的 HTML 元素, 并模拟用户交互, 例如在文本框中输入文本, 然后单击按钮. 在完成操作后, 你可以验证网页上的结果是否符合预期结果.
在以下代码片段中, 这个类测试一个 WebView 组件, 该组件的 id 值 "WebView" 在被测试的活动中.
verifyValidInputYieldsSuccesfulSubmission()
测试选择网页上的 < input > 元素, 输入一些文本, 并检查出现在另一个元素中的文本.
- @LargeTest
- @RunWith(AndroidJUnit4.class)
- public class WebViewActivityTest {
- private static final String MACCHIATO = "Macchiato";
- private static final String DOPPIO = "Doppio";
- @Rule
- public ActivityTestRule mActivityRule =
- new ActivityTestRule(WebViewActivity.class,
- false /* Initial touch mode */, false /* launch activity */) {
- @Override
- protected void afterActivityLaunched() {
- // Enable JavaScript.
- onWebView().forceJavascriptEnabled();
- }
- }
- @Test
- public void typeTextInInput_clickButton_SubmitsForm() {
- // Lazily launch the Activity with a custom start Intent per test
- mActivityRule.launchActivity(withWebFormIntent());
- // Selects the WebView in your layout.
- // If you have multiple WebViews 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
- .perform(clearElement())
- // Enter text into the input element
- .perform(DriverAtoms.webKeys(MACCHIATO))
- // Find the submit button
- .withElement(findElement(Locator.ID, "submitBtn"))
- // Simulate a click via JavaScript
- .perform(webClick())
- // Find the response element by ID
- .withElement(findElement(Locator.ID, "response"))
- // Verify that the response page contains the entered text
- .check(webMatches(getText(), containsString(MACCHIATO)));
- }
- }
有关 Espresso Web 的更多信息, 请参阅 Android 测试支持库网站上的 Espresso Web 文档. 您也可以将此代码段作为 Espresso Web 代码示例的一部分下载.
验证结果
调用
ViewInteraction.check()
或
DataInteraction.check()
方法来声明 UI 中的视图匹配某个预期的状态. 必须传递给 ViewAssertion 对象作为参数. 如果断言失败, Espresso 将抛出一个 AssertionFailedError.
ViewAssertions 类提供了用于指定公共断言的帮助器方法列表. 你可以使用的断言包括:
doesNotExist: 断言当前视图层次结构中没有与指定条件匹配的视图.
matches: 断言指定的视图存在于当前的视图层次结构中, 并且其状态匹配给定的 Hamcrest 匹配器.
selectedDescendentsMatch: 声明指定的父视图的子视图存在, 并且它们的状态匹配给定的 Hamcrest 匹配器.
以下代码片段显示如何检查用户界面中显示的文本与先前在 EditText 字段中输入的文本具有相同的值.
- public void testChangeText_sameActivity() {
- // Type text and then press the button.
- ...
- // Check that the text was changed.
- onView(withId(R.id.textToBeChanged))
- .check(matches(withText(STRING_TO_BE_TYPED)));
- }
在设备或模拟器上运行 Espresso 测试
你可以从 Android Studio 或从命令行运行 Espresso 测试. 确保将 AndroidJUnitRunner 指定为项目中的默认检测工具.
要运行 Espresso 测试, 请按照前面章节介绍的步骤运行已测试的测试.
来源: http://www.bubuko.com/infodetail-2600132.html