相比于服务器测试的高度自动化,Android app的测试因其交互性复杂,运行需要Android环境,并且测试用例编写比较琐碎等原因,在大部分公司通常单纯由测试人员手工完成,自动化程度比较低。每次版本迭代需要把所有的路径都要覆盖一遍,费时费力,如果能将一部分重复单调的流程通过测试用例进行覆盖,就可以较大程度的减少测试人员的重复工作,从而将更多时间花在新功能的测试上。本文将j简要介绍Android测试技术。
Android的测试分为Local Unit Test和Instrumented Test,Local Unit Test运行在JVM上,包括所有不需要Android环境的测试用例。Instrumented Test运行在Android真机或Android模拟器上,包括需要Android环境的测试用例。Instrumented Test又分为Instrumented Unit Test和UI Test,Instrumented Unit Test包括所有跟UI无关的测试用例,UI Test包括所有含UI交互的测试用例。下面将分类介绍各种测试用例。
Local Unit test
运行在java虚拟机上,Android环境无关的代码测试,不需要Android设备,简单高效。测试代码放在 module-name/src/test/java/目录下。
首先在gradle中添加如下配置:
dependencies {
// Required -- JUnit 4 framework
testCompile 'junit:junit:4.12'
// Optional -- Mockito framework
testCompile 'org.mockito:mockito-core:1.10.19'
}
JUnit是单元测试使用的框架,Mockito工具可以mock简单的Android环境。
@RunWith(MockitoJUnitRunner.class)
public class MainActivityTest {
private static final String FAKE_STRING = "Hello world!";
@Mock
Context mMockContext;
@Test
public void testAdd_Without_Mock() throws Exception {
assertEquals(MainActivity.add(1, 3), 4);
}
@Test
public void testCombineString_With_Mock() {
when(mMockContext.getString(R.string.hello_word)).thenReturn(FAKE_STRING);
ClassUnderTest classUnderTest = new ClassUnderTest(mMockContext);
String result = classUnderTest.combineString("Jack!");
assertEquals(result, "Hello world! Jack!");
}
}
上面的代码中包含两个测试用例,第一个是不需要Mock Android环境的测试用例,第二个需要Mock。在testCombineString_With_Mock中,首先通过when指定Mock的Context调用getString函数时的返回值,相当于构造了一个“假的”Context。这样当ClassUnderTest的实例执行combineString函数时,通过context.getString(R.string.hello_word)返回的就是我们指定的值,从而避免了真正去构造一个Context。在测试文件上右键,Run,就可以看到测试结果。
Instrumented tests
运行在Dalvik虚拟机上,Android环境相关,需要运行在Android设备上或模拟器上。测试代码放在module-name/src/androidTest/java/目录下。
首先配置gradle:
dependencies {
...
androidTestCompile 'com.android.support:support-annotations:23.4.0'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
}
Instrumented Unit Test
@RunWith(AndroidJUnit4.class)
public class ApplicationTest {
@Rule
public ActivityTestRule<MainActivity> mMainActivity = new ActivityTestRule<>(MainActivity.class);
@Test
public void combineString() {
ClassUnderTest classUnderTest = new ClassUnderTest(mMainActivity.getActivity());
String result = classUnderTest.combineString("Jack!");
assertEquals(result, "Hello world! Jack!");
}
...
}
由于这个测试用例运行在Android环境下,所以相比于Local Unit Test,它不需要Mock Context,直接将生成的Activity传入即可。
UI Test
UI Test分为app内UI测试和不同app间UI测试,前者使用Espresso库,后者使用UI Automator库。
- app内UI测试
@RunWith(AndroidJUnit4.class)
public class ApplicationTest {
@Rule
public ActivityTestRule<MainActivity> mMainActivity = new ActivityTestRule<>(MainActivity.class);
@Test
public void onTextViewClickedTest() {
onView(withId(R.id.input_et)).perform(typeText("hello world"), closeSoftKeyboard());
onView(withId(R.id.clickme_tv)).perform(click()).check(matches(withText("Submit success!")));
}
...
}
利用Espresso进行UI交互模拟使用下面的代码,详细用法可参考这里。
onView(ViewMatcher) //1.匹配View
.perform(ViewAction) //2.执行View行为
.check(ViewAssertion); //3.验证View
- 不同app间UI测试
较少使用,这里不做介绍。
本文Github Demo地址
参考:
https://developer.android.com/training/testing/index.html
https://segmentfault.com/a/1190000006031195