Android测试(五):Instrumented 单元测试
Instrumented 单元测试是在真机并且可以上运行的测试,它利用Android框架API和支持的API(如Android测试支持库)。如果你的测试需要访问工具信息(例如目标应用程序的Context),需要真正实现 Android 框架组件(如Parcelable或SharedPreferences对象),则应该创建 Instrumented 单元测试。
如果你愿意,可以自由使用一个模拟框架模拟任何依赖关系。
设置测试环境
在你的 Android Studio 项目中,你必须将模拟测试的源文件存储在 module-name/src/androidTest/java/ 中。创建新项目时该目录已经存在,并包含示例代码。
在开始之前,你应该下载 Android 测试支持库安装程序,应该让你快速构建和运行应用程序的检测代码。测试支持库包括用于功能性 UI 测试(Espresso 和 UI Automator)的JUnit 4测试运行器(AndroidJUnitRunner)和API。
还需要为项目 Android 测试依赖项,以使用测试运行程序和测试支持库提供的 API 规则。 配置简化测试开发,还应该包含 Hamcrest 库,它让你使用 Hamcrest 匹配器 API 创建更灵活的断言。
在你的App的环境build.gradle文件中将这些库指定为依赖项:
dependencies {androidTestCompile 'com.android.support:support-annotations:24.0.0'androidTestCompile 'com.android.support.test:runner:0.5'androidTestCompile 'com.android.support.test:rules:0.5'// Optional -- Hamcrest libraryandroidTestCompile 'org.hamcrest:hamcrest-library:1.3'// Optional -- UI testing with EspressoandroidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'// Optional -- UI testing with UI AutomatorandroidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
}
警告:如果构建包含支持注解库的编译依赖项和 espresso-core 库的编译依赖项,则由于依赖项,构建可能会失败。请按照以下步骤更新对 espresso-core 的依赖关系:
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {exclude group: 'com.android.support', module: 'support-annotations'
})
要使用JUnit 4测试类,请确保将AndroidJUnitRunner指定为项目中的默认测试工具运行器,方法是在应用程序的模块级build.gradle文件中包含以下设置:
android {defaultConfig {testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"}
}
创建一个仪器化的单元测试类
你的 Instrumented 单元测试类应该写成 JUnit 4 测试类。要了解创建 JUnit 4 测试类和使用 JUnit 4 断言和注释的更多信息,请参阅创建本地单元测试类。
要创建一个 Instrumented 的 JUnit 4 测试类,在测试类定义的添加添加@RunWith(AndroidJUnit4.class)注释。还需要将 Android 测试支持库中提供的 AndroidJUnitRunner 类指定为默认测试运行器。测试入门中步骤进行了更详细的介绍。
以下示例显示如何写一个内置的单元测试,以确保LogHistory正确类实现了Parcelable接口:
import android.os.Parcel;
import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;@RunWith(AndroidJUnit4.class)
@SmallTest
public class LogHistoryAndroidUnitTest {public static final String TEST_STRING = "This is a string";public static final long TEST_LONG = 12345678L;private LogHistory mLogHistory;@Beforepublic void createLogHistory() {mLogHistory = new LogHistory();}@Testpublic void logHistory_ParcelableWriteRead() {// Set up the Parcelable object to send and receive.mLogHistory.addEntry(TEST_STRING, TEST_LONG);// Write the data.Parcel parcel = Parcel.obtain();mLogHistory.writeToParcel(parcel, mLogHistory.describeContents());// After you're done with writing, you need to reset the parcel for reading.parcel.setDataPosition(0);// Read the data.LogHistory createdFromParcel = LogHistory.CREATOR.createFromParcel(parcel);List<Pair<String, Long>> createdFromParcelData = createdFromParcel.getData();// Verify that the received data is correct.assertThat(createdFromParcelData.size(), is(1));assertThat(createdFromParcelData.get(0).first, is(TEST_STRING));assertThat(createdFromParcelData.get(0).second, is(TEST_LONG));}
}
创建一个测试套件
要组织测试单元测试的执行,可以将一组中测试集合在一个测试套件类中,将这些测试一起运行。测试套件可以约束;测试套件可以将其他测试套件套装,赋予所有组件测试类一起运行。
测试套件包含测试包中,数据主应用程序包。根据目的,测试套件包名在.suite结尾(例如,com.example.android.testing.mysample.suite)。
以下示例显示了如何实现命名UnitTestSuite的测试套件,该测试套件将CalculatorInstrumentationTest和CalculatorAddParameterizedTest测试类表现并运行。
import com.example.android.testing.mysample.CalculatorAddParameterizedTest;
import com.example.android.testing.mysample.CalculatorInstrumentationTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;// Runs all unit tests.
@RunWith(Suite.class)
@Suite.SuiteClasses({CalculatorInstrumentationTest.class,CalculatorAddParameterizedTest.class})
public class UnitTestSuite {}
运行仪器单元测试
要运行仪器测试,请遵循以下步骤:
1、通过点击工具确保进度的“同步项目”,您的项目与Gradle同步。
2、以以下一种方式运行测试:
- 要运行测试请打开项目窗口,然后单击“运行”。
- 要测试类中的所有方法,请详细方法文档中的类或,然后单击“运行”。
- 要在目录中运行所有测试,请说明目录并选择“运行测试”。
Gradle的Android插件安装位置默认目录(src/androidTest/java/)中的测试代码,构建测试APK和生产APK,在连接的真机或上安装两个APK,并运行测试。Android Studio在然后“运行”窗口中显示测试执行结果。
注意:在运行或调试测试工具时,Android Studio 不会为即时运行注入所需的额外方法,并关闭该特性。
Android测试(六):Android UI自动化测试
用户界面(UI)测试可以确保你的应用程序满足其功能要求,并达到用户最可能成功采用的高质量标准。
UI测试的一种方法是简单地让人类测试人员在目标应用程序上执行一组用户操作,并验证其行为是否正确。 但是,这种手动方法可能耗时、乏味、且容易出错。更有效的方法是编写您的UI测试,以便用户操作以自动方式执行。 自动化方法使您能够以可重复的方式快速可靠地运行测试。
注意:强烈建议您使用Android Studio来构建测试应用程序,因为它提供了项目设置,包含库和包非常方便。 这个里假定你正在使用Android Studio。
要使用Android Studio自动执行UI测试,请在单独的Android测试文件夹src/androidTest/java中实现测试代码。针对Gradle的Android插件将根据你的测试代码构建测试应用程序,然后将测试应用程序加载到与目标应用程序相同的设备上。 在测试代码中,可以使用UI测试框架来模拟目标应用程序上的用户交互,以执行覆盖特定使用场景的测试任务。
为了测试Android应用程序,通常会创建这些类型的UI自动化测试:
单个应用程序的UI测试: 这种类型的测试验证当用户执行特定操作或在其活动中输入特定内容时,目标验证应用程序的行为是否符合预期。它允许你检查目标应用程序是否返回正确的UI输出,以响应应用程序活动中的用户交互。像Espresso这样的UI测试框架允许以编程方式模拟用户操作并测试复杂的应用内用户交互。
跨越多个应用程序的UI测试: 这种类型的测试验证不同用户应用程序之间或用户应用程序与系统应用程序之间交互的正确行为。例如,可能想要测试你的相机应用程序与第三方社交媒体应用程序或默认的Android照片应用程序正确共享图像。支持跨应用程序交互的UI测试框架(如UI Automator)允许你为这些方案创建测试。
Android测试(七):Espresso 自动化测试
在单个应用程序中测试用户交互有助于确保用户在与应用程序进行交互时不会遇到意外的结果,或遇到糟糕的体验。 如果需要验证应用的UI功能是否正常,则应该养成创建用户界面(UI)测试的习惯。
Espresso 测试框架,由Android测试支持库提供,用于编写UI测试的API来模拟单个应用程序内的用户交互。Espresso测试可以在运行Android 2.3.3(API等级10)及更高版本的设备上运行。 使用Espresso的一个关键好处是,它提供了测试操作与正在测试的应用程序的用户界面的自动同步。 Espresso检测主线程是否处于空闲状态,以便能够在适当的时候运行测试命令,从而提高测试的可靠性。此功能还可以减轻在测试代码中添加任何计时变通方法如Thread.sleep() 的麻烦。
Espresso测试框架基于instrumentation的API,并通过AndroidJUnitRunner运行测试。
设置Espresso
在使用Espresso构建UI测试之前,请确保配置测试源代码位置和项目依赖关系。
在Android应用程序模块的build.gradle文件中,必须设置对Espresso库的依赖关系引用:
dependencies {// Other dependencies ...androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
}
关闭测试设备上的动画 - 在测试设备中打开系统动画可能会导致意外的结果,或者可能导致测试失败。 通过打开“开发人员”选项关闭“设置”中的动画,并关闭以下所有选项:
-
窗口动画比例
-
过渡动画比例
-
动画师持续时间比例
如果你希望将项目设置为使用核心API提供的Espresso功能以外的功能,
创建一个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;@Rulepublic ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);@Beforepublic void initValidString() {// Specify a valid string.mStringToBetyped = "Espresso";}@Testpublic 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 匹配器在应用程序中指定视图和适配器。
要查找视图,请调用onView()方法并传递一个视图匹配器,该视图匹配器指定要定位的视图。 这在指定视图匹配器中有更详细的描述。 onView()方法返回ViewInteraction对象,允许测试与视图进行交互。 但是,如果要在RecyclerView布局中查找视图,则调用onView()方法可能不起作用。 在这种情况下,请按照在AdapterView中查找视图中的说明进行操作。
注意:onView()方法不检查你指定的视图是否有效。相反,Espresso只搜索当前的视图层次结构,使用matcher提供的视图。如果没有找到匹配,该方法将抛出一个NoMatchingViewException。
下面的代码片段展示了如何编写一个测试来访问EditText字段,输入一个文本字符串,关闭虚拟键盘,然后执行按钮单击。 ```Java 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),如下例所示: java onView(withId(R.id.button_signin)); Android资源ID不保证是唯一的。 如果测试尝试匹配多个视图使用的资源ID,则Espresso会引发AmbiguousViewMatcherException。
- 使用Hamcrest Matchers类。可以使用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公开的字符串列表。 java 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. */@Rulepublic IntentsTestRule≶MainActivity> mIntentsRule =new IntentsTestRule≶>(MainActivity.class);@Testpublic 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";@Rulepublic ActivityTestRule mActivityRule =new ActivityTestRule(WebViewActivity.class,false /* Initial touch mode */, false /* launch activity */) {@Overrideprotected void afterActivityLaunched() {// Enable JavaScript.onWebView().forceJavascriptEnabled();}}@Testpublic void typeTextInInput_clickButton_SubmitsForm() {// Lazily launch the Activity with a custom start Intent per testmActivityRule.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测试,请按照前面章节介绍的步骤运行已测试的测试。
Android测试(八):UI Automator 自动化测试
涉及跨多个应用程序的用户交互的用户界面(UI)测试可以验证应用程序在用户流量跨越其他应用程序或进入系统UI时的行为。 这种用户流程的一个例子是一个消息应用程序,它允许用户输入文本消息,启动Android联系人选择器,以便用户可以选择收件人发送消息,然后将控制权返回给用户的原始应用程序并提交消息。
这一小节介绍如何使用Android测试支持库提供的UI Automator测试框架编写此类UI测试。 UI Automator API可让你与设备上的可见元素进行交互,而不管哪个Activity处于焦点。你的测试可以使用方便的描述符(如该组件中显示的文本或其内容描述)查找UI组件。 UI Automator测试可以在运行Android 4.3(API级别18)或更高版本的设备上运行。
UI Automator测试框架是基于 instrumentation的API,并与AndroidJUnitRunner测试运行器一起使用。
设置UI Automator
在使用UI Automator构建UI测试之前,请确保配置测试源代码位置和项目依赖关系,如前面章节中所述。
在Android应用程序模块的build.gradle文件中,必须设置对UI Automator库的依赖关系引用:
dependencies {...androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
}
为了优化您的UI Automator测试,您应该首先检查目标应用程序的UI组件,并确保它们可以访问。 这些优化技巧将在下面两节中介绍。
查看设备上的UI
在设计您的测试之前,检查设备上可见的UI组件。 为确保您的UI Automator测试可以访问这些组件,请检查这些组件是否具有可见的文本标签、android:contentDescription 值。
uiautomatorviewer工具提供了一个方便的可视化界面来检查布局层次结构,并查看设备前台中可见的UI组件的属性。这个信息可以让你使用UI Automator创建更细致的测试。例如,可以创建一个匹配特定可见属性的UI选择器。
启动uiautomatorviewer工具:
1.在物理设备上启动目标应用程序。
2.将设备连接到你的开发机器。
3.打开终端窗口并导航到<android-sdk> / tools /目录。
4.使用以下命令运行该工具:
$ uiautomatorviewer
要查看您的应用程序的UI属性:
1.在uiautomatorviewer界面中,点击 Device Screensho 按钮。
2.将鼠标悬停在左侧面板中的快照上,查看由uiautomatorviewer工具标识的UI组件。 属性列在右下方的面板中,右上方的布局层次中列出。
3.或者,单击 Toggle NAF Nodes 按钮以查看UI Automator无法访问的UI组件。 这些组件只有有限的信息可用。
确保你的Activity是可访问的
UI Automator测试框架对已实施Android辅助功能的应用程序执行得更好。当你使用View类型的UI元素或SDK或Support Library中的View的子类时,不需要实现可访问性支持,因为这些类已经为你完成了。
但是,有些应用程序使用自定义UI元素来提供更丰富的用户体验。 这些元素不会提供自动的可访问性支持。如果你的应用程序包含不是来自SDK或支持库的View子类的实例,请确保通过完成以下步骤将可访问性功能添加到这些元素:
1.创建一个扩展ExploreByTouchHelper的具体类。
2.通过调用setAccessibilityDelegate()将新类的实例与特定的自定义UI元素相关联。
有关将辅助功能添加到自定义视图元素的其他指导,请参阅构建可访问自定义视图要详细了解Android上可访问性的一般最佳实践,请参阅使应用程序更易于访问。
创建一个UI Automator测试类
UI Automator测试类应该像JUnit 4测试类一样编写。 要了解有关创建JUnit 4测试类和使用JUnit 4断言和注释的更多信息,请参阅创建测试单元测试类。
在测试类定义的开始处添加@RunWith(AndroidJUnit4.class)注释。 还需要将Android测试支持库中提供的AndroidJUnitRunner类指定为您的默认测试运行器。 在设备或模拟器上运行UI Automator测试中将更详细地描述此步骤。
在UI Automator测试类中实现以下编程模型:
1.通过调用getInstance()方法并传递一个Instrumentation对象作为参数,获取一个UiDevice对象来访问要测试的设备。
2.通过调用findObject()方法,获取UiObject对象以访问设备上显示的UI组件(例如前景中的当前视图)。
3.通过调用UiObject方法来模拟特定的用户交互以在该UI组件上执行; 例如,调用performMultiPointerGesture()来模拟多点触摸手势,setText()来编辑文本字段。你可以根据需要重复调用步骤2和3中的API,以测试涉及多个UI组件或用户操作序列的更复杂的用户交互。
4.在执行这些用户交互之后,检查UI是否反映了预期的状态或行为。
以下各节将详细介绍这些步骤。
访问UI组件
UiDevice对象是访问和操作设备状态的主要方式。在测试中调用UiDevice方法来检查各种属性的状态,例如当前方向或显示大小。 可以使用UiDevice对象执行设备级别的操作,例如强制设备进入特定的旋转状态,按下D-pad硬件按钮,然后按Home(主页)和Menu(菜单)按钮。
从设备的主屏幕开始测试是一种很好的做法。从主屏幕(或在设备中选择的其他位置),你可以调用UI Automator API提供的方法来选择特定的UI元素并与之交互。
下面的代码片段显示了测试如何得到一个UiDevice的实例,并模拟按下一个主页按钮:
import org.junit.Before;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.Until;
...@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
public class ChangeTextBehaviorTest {private static final String BASIC_SAMPLE_PACKAGE= "com.example.android.testing.uiautomator.BasicSample";private static final int LAUNCH_TIMEOUT = 5000;private static final String STRING_TO_BE_TYPED = "UiAutomator";private UiDevice mDevice;@Beforepublic void startMainActivityFromHomeScreen() {// Initialize UiDevice instancemDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());// Start from the home screenmDevice.pressHome();// Wait for launcherfinal String launcherPackage = mDevice.getLauncherPackageName();assertThat(launcherPackage, notNullValue());mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),LAUNCH_TIMEOUT);// Launch the appContext context = InstrumentationRegistry.getContext();final Intent intent = context.getPackageManager().getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);// Clear out any previous instancesintent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);context.startActivity(intent);// Wait for the app to appearmDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),LAUNCH_TIMEOUT);}
}
在示例中,@SdkSuppress(minSdkVersion = 18)语句有助于确保测试只能在Android 4.3(API级别18)或更高级别的设备上运行,正如UI Automator框架所要求的那样。
使用findObject()方法来检索一个UiObject,它表示一个匹配给定选择器条件的视图。根据需要重复使用在应用程序测试的其他部分创建的UIObject实例。 请注意,每次测试使用UiObject实例单击UI元素或查询属性时,UI Automator测试框架都会在当前显示中搜索匹配项。
以下片段显示了测试如何构建表示应用程序中的“取消”按钮和“确定”按钮的UIObject实例。
UiObject cancelButton = mDevice.findObject(new UiSelector().text("Cancel")).className("android.widget.Button"));
UiObject okButton = mDevice.findObject(new UiSelector().text("OK")).className("android.widget.Button"));// Simulate a user-click on the OK button, if found.
if(okButton.exists() && okButton.isEnabled()) {okButton.click();
}
指定选择器
如果要访问应用程序中的特定UI组件,请使用UiSelector类。 这个类表示对当前显示的UI中特定元素的查询。
如果找到多个匹配元素,则层次结构中的第一个匹配元素将作为目标UiObject返回。 构建UiSelector时,可以将多个属性链接在一起以优化搜索。 如果找不到匹配的UI元素,则抛出UiAutomatorObjectNotFoundException。
你可以使用childSelector()方法来嵌套多个UiSelector实例。 例如,下面的代码示例显示如何测试搜索以在当前显示的UI中查找第一个ListView,然后在该ListView内搜索以查找具有文本属性Apps的UI元素。
UiObject appItem = new UiObject(new UiSelector().className("android.widget.ListView").instance(0).childSelector(new UiSelector().text("Apps")));
最佳做法是,在指定选择器时,应使用资源ID(如果将其分配给UI元素)而不是文本元素或内容描述符。并非所有元素都有文本元素(例如,工具栏中的图标)。文本选择器很脆弱,如果UI发生细微的变化,可能会导致测试失败。他们也可能不能跨越不同的语言; 您的文本选择器可能不匹配翻译的字符串。
在选择器条件中指定对象状态可能很有用。例如,如果要选择所有选中的元素的列表,以便取消选中它们,请使用参数设置为true的checked()方法。
执行操作
一旦你的测试获得了一个UIObject对象,可以调用UIObject类中的方法在该对象表示的UI组件上执行用户交互。指定如下操作:
- click():单击UI元素的可见边界的中心。
- dragTo():将此对象拖动到任意坐标。
- setText():清除字段内容后,设置可编辑字段中的文本。 相反,clearTextField()方法会清除可编辑字段中的现有文本。
- swipeUp():对UiObject执行滑动操作。 同样,swipeDown(),swipeLeft()和swipeRight()方法也会执行相应的操作。
UI Automator测试框架允许您通过getContext()获取Context对象来发送Intent或启动一个Activity,而无需使用shell命令。
以下片段显示了测试如何使用Intent来启动测试中的应用程序。 这种方法是有用的,当你只是在测试计算器应用程序感兴趣,并不关心发射器。
public void setUp() {...// Launch a simple calculator appContext context = getInstrumentation().getContext();Intent intent = context.getPackageManager().getLaunchIntentForPackage(CALC_PACKAGE);intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);// Clear out any previous instancescontext.startActivity(intent);mDevice.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
}
对集合执行操作
如果要模拟项目集合(例如,音乐相册中的歌曲或收件箱中的电子邮件列表)上的用户交互,请使用UiCollection类。要创建UiCollection对象,请指定一个UiSelector,用于搜索UI容器或其他子UI元素的包装器,例如包含子UI元素的布局视图。
以下代码片段显示了测试如何构建UiCollection来表示在FrameLayout中显示的视频专辑:
UiCollection videos = new UiCollection(new UiSelector().className("android.widget.FrameLayout"));// Retrieve the number of videos in this collection:
int count = videos.getChildCount(new UiSelector().className("android.widget.LinearLayout"));// Find a specific video and simulate a user-click on it
UiObject video = videos.getChildByText(new UiSelector().className("android.widget.LinearLayout"), "Cute Baby Laughing");
video.click();// Simulate selecting a checkbox that is associated with the video
UiObject checkBox = video.getChild(new UiSelector().className("android.widget.Checkbox"));
if(!checkBox.isSelected()) checkbox.click();
在可滚动视图上执行操作
使用UiScrollable
类模拟垂直或水平滚动显示。 当UI元素位于屏幕外并且需要滚动以将其显示在视图中时,此技术很有用。
以下代码片段显示了如何模拟向下滚动“Settings ”菜单并点击“About tablet option”:
UiScrollable settingsItem = new UiScrollable(new UiSelector().className("android.widget.ListView"));
UiObject about = settingsItem.getChildByText(new UiSelector().className("android.widget.LinearLayout"), "About tablet");
about.click();
验证结果
InstrumentationTestCase扩展了TestCase,因此你可以使用标准的JUnit Assert
方法来测试应用程序中的UI组件,以返回预期的结果。
以下片段显示了如何在计算器应用程序中找到几个按钮,然后按顺序点击它们,然后验证是否显示了正确的结果。
private static final String CALC_PACKAGE = "com.myexample.calc";public void testTwoPlusThreeEqualsFive() {// Enter an equation: 2 + 3 = ?mDevice.findObject(new UiSelector().packageName(CALC_PACKAGE).resourceId("two")).click();mDevice.findObject(new UiSelector().packageName(CALC_PACKAGE).resourceId("plus")).click();mDevice.findObject(new UiSelector().packageName(CALC_PACKAGE).resourceId("three")).click();mDevice.findObject(new UiSelector().packageName(CALC_PACKAGE).resourceId("equals")).click();// Verify the result = 5UiObject result = mDevice.findObject(By.res(CALC_PACKAGE, "result"));assertEquals("5", result.getText());
}
在设备或模拟器上运行UI Automator测试
你可以从Android Studio或从命令行运行UI Automator测试。 确保将AndroidJUnitRunner指定为项目中的默认检测工具。
要运行UI Automator测试,请按照前面章节中所述的步骤来运行测试。
感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取