相比於服務器測試的高度自動化,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測試
較少使用,這裏不做介紹。
參考:
https://developer.android.com/training/testing/index.html
https://segmentfault.com/a/1190000006031195