5.2使用Android测试支持库进行测试
问题
你想测试你的应用程序的Android组件。

使用新的测试类来实现应用程序的JUnit风格测试。
讨论
首先,关于术语的元注释:测试Android组件,如活动或服务,需要将应用程序部署到连接的设备或模拟器。测试库基于JUnit,但是这些不是严格意义上的单元测试。它们是集成测试或功能测试,取决于您如何使用这些术语。
由于这里的方法是以编程方式驱动已部署的应用程序,并检查UI是否正确更改,因此此处将优先使用术语“功能”。不过,您将在文档中看到经常使用的术语。
尽管在AndroidJUnitRunner和其他测试类中有单词“unit”,Android测试本身就是功能。它们需要仿真器或连接的设备才能运行。
Android测试支持库作为可选的依赖关系通过SDK Manager添加,如图5-6所示。
测试是“Android Support Repository”下载的一部分,如图5-6所示。测试类驻留在android.support.test包中。
文档显示,要将所有相关类添加到Gradle构建文件中,请使用示例5-7中的依赖关系。
实例5-7。 Android测试支持库的Gradle依赖项

dependencies {
androidTestCompile 'com.android.support.test:runner:0.3'
// Set this dependency to use JUnit 4 rules
androidTestCompile 'com.android.support.test:rules:0.3'
}



图5-6。使用SDK管理器添加Android测试支持库


AndroidJUnitRunner类支持JUnit 4注释。要使用它,您可以将@RunWith注释从JUnit添加到测试类,或者可以将设置添加到Gradle构建文件的defaultConfig块。


实例5-8。默认情况下使用AndroidJUnitRunner


android {
defaultConfig {
// ... other settings ...
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
}
}

使用测试支持类在布局上测试标签特别容易。示例5-9中显示了一个示例。


实例5-9。测试组件标签


@MediumTest //1
@RunWith(AndroidJUnit4.class) //2
public class MyActivityLayoutTest
extends ActivityInstrumentationTestCase2<MyActivity> {
private MyActivity activity;
private TextView textView;
private EditText editText;
private Button helloButton;
public MyActivityLayoutTest() {
super(MyActivity.class);
}
@Before
public void setUp() throws Exception {
super.setUp()
injectInstrumentation(InstrumentationRegistry.getInstrumentation());//3
activity = getActivity();
textView = (TextView) activity.findViewById(R.id.text_view);
editText = (EditText) activity.findViewById(R.id.edit_text);
helloButton = (Button) activity.findViewById(R.id.hello_button);
}
@After
public void tearDown() throws Exception {
super.tearDown();
}
@Test
public void testPreconditions() {
assertNotNull("Activity is null", activity);
assertNotNull("TextView is null", textView);
assertNotNull("EditText is null", editText);
assertNotNull("HelloButton is null", helloButton);
}
@Test
public void textView_label() {
final String expected = activity.getString(R.string.hello_world);
final String actual = textView.getText().toString();
assertEquals(expected, actual);
}
@Test
public void editText_hint() {
final String expected = activity.getString(R.string.name_hint);
final String actual = editText.getHint().toString();
assertEquals(expected, actual);
}
@Test
public void helloButton_label() {
final String expected = activity.getString(R.string.hello_button_label);
final String actual = helloButton.getText().toString();
assertEquals(expected, actual);
}
}

1预期持续时间为@SmallTest,@MediumTest和@LargeTest


2使用Android的JUnit 4 runner


3需要为新的JUnit 4转轮


新的AndroidJUnitRunner是Android支持测试库的一部分。它添加JUnit 4支持,以便测试可以注释,而不是使用旧的JUnit 3命名约定指定。它还有其他额外的功能。有关详细信息,请参阅Android测试支持库文档。


在示例5-9中,属性表示用户界面上的小部件。 @Before方法查找它们并将它们分配给属性。文档建议使用testPreconditions测试,如图所示,只是为了演示小部件被找到。这个测试与任何其他测试没有什么不同,但是在那里的失败使得很容易看出哪里出错了。


其他测试都从字符串资源中查找字符串,并将它们与实际小部件上的标签进行比较。注意,这里没有修改任何内容 - 测试本质上是只读的。


最后,@MediumTest注释用于指示测试方法的大小。测试


只需要几毫秒的时间被标记为@SmallTest,那些花费100毫秒的时间是@MediumTest,而较长的时间被标记为@LargeTest。


从Gradle,运行测试需要连接的设备或模拟器通过connectedCheck任务完成。


运行connectedCheck任务以并发地对所有仿真器和连接的设备执行测试。


示例5-10中显示了示例执行。样本测试在两个单独的仿真器上同时运行。


实例5-10。从Gradle执行测试

> ./gradlew connectedCheck
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:checkDebugManifest
:app:prepareDebugDependencies
// ... lots of tasks ...
:app:packageDebugAndroidTest UP-TO-DATE
:app:assembleDebugAndroidTest UP-TO-DATE
:app:connectedDebugAndroidTest
:app:connectedAndroidTest
:app:connectedCheck
BUILD SUCCESSFUL

输出报告驻留在http://robolectric.orgapp/build/reports/androidTests/ connected目录中。 示例输出报告如图5-7所示。




图5-7。 通过测试组织的示例测试输出


示例输出显示模拟器名称和所有测试的结果。 单击“设备”按钮可切换输出以按设备组织,如图5-8所示。


Android支持测试库中的类可以做得更多,但是测试开始变得很复杂。 当你想通过添加数据,点击按钮和检查结果来驱动UI时,还有一些替代库,例如Robotium和Espresso,使得这个过程更容易。 使用这些库的配方在“另请参见”部分中引用。




图5-8。 按设备组织的测试输出示例