單元測試的重要的和必要性這里不在強(qiáng)調(diào)斋日,本文介紹幾個(gè)常用的單元測試的框架
JUnit4
JUnit4是一個(gè)java的單元測試框架饰恕,多數(shù)Java的開發(fā)環(huán)境都已經(jīng)集成了JUnit作為單元測試的工具挠羔,android studio默認(rèn)繼承了JUNit4
testImplementation 'junit:junit:4.12'
JUnit4主要是通過注解的方式來識別測試方法,下面介紹幾個(gè)常用的方法以及它的作用:
- @BeforeClass 在執(zhí)行所有測試方法之前執(zhí)行埋嵌,只執(zhí)行一次破加,對應(yīng)方法必須是靜態(tài)方法
- @Before 在任意使用@Test注解標(biāo)注方法執(zhí)行之前執(zhí)行
- @Test 測試方法
- @After 在任意使用@Test注解標(biāo)注方法執(zhí)行之后執(zhí)行
- @AfterClass 在執(zhí)行所有測試方法之后執(zhí)行,只執(zhí)行一次莉恼,對應(yīng)方法必須是靜態(tài)方法
了解完以上的信息還沒有完結(jié)拌喉,單元測試還有很重要的一點(diǎn)驗(yàn)證結(jié)果,一般是通過一些assert方法來完成的俐银,JUnit為我們提供的assert方法,多數(shù)都在Assert這個(gè)類里面
- Assert.assertEquals 驗(yàn)證執(zhí)行結(jié)果與期盼結(jié)果比較端仰,這個(gè)方法的參數(shù)有很多種捶惜,根據(jù)需要使用
- Assert.assertFalse 驗(yàn)證參數(shù)為false
- Assert.assertNotNull 驗(yàn)證參數(shù)不為空
- Assert.assertNotSame 參數(shù)中的兩個(gè)對象不是同一個(gè)對象
- Assert.assertNull 驗(yàn)證參數(shù)為空
- Assert.assertSame 參數(shù)中的兩個(gè)對象是同一個(gè)對象
- Assert.assertThat 實(shí)際情況滿足匹配器給出的條件
- Assert.assertTrue 驗(yàn)證參數(shù)為true
由于很多地方用到了Assert.assertThat方法,下面列一下啊Matcher常用的方法
- Matcher.allOf
- Matcher.anyOf
- Matcher.both
- Matcher.containsString
- Matcher.describedAs
- Matcher.either
- Matcher.endsWith
- Matcher.equalTo
- Matcher.instanceOf
- Matcher.is
- Matcher.hasItem
JUnit單元測試時(shí)是不能使用Android相關(guān)的類的荔烧,下面就來認(rèn)識一下Robolectric框架
Robolectric
Robolectric框架是針對android的測試框架吱七,使用Robolectric框架進(jìn)行單元測試不用依賴真機(jī)或者模擬器,Robolectric支持單元測試范圍從Activity的跳轉(zhuǎn)鹤竭、Activity展示View(包括菜單)和Fragment到View的點(diǎn)擊觸摸以及事件響應(yīng)踊餐,同時(shí)Robolectric也能測試Toast和Dialog。對于需要網(wǎng)絡(luò)請求數(shù)據(jù)的測試臀稚,Robolectric可以模擬網(wǎng)絡(luò)請求的response吝岭。對于一些Robolectric不能測試的對象,比如ConcurrentTask,可以通過自定義Shadow的方式現(xiàn)實(shí)測試窜管。下面將著重介紹Robolectric的常見用法散劫。
引入
testCompile "org.robolectric:robolectric:3.6.1"
官方給出的demo
<pre>
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
public class MyActivityTest {
@Test
public void clickingButton_shouldChangeResultsViewText() throws Exception {
Activity activity = Robolectric.setupActivity(MyActivity.class);
Button button = (Button) activity.findViewById(R.id.press_me_button);
TextView results = (TextView) activity.findViewById(R.id.results_text_view);
button.performClick();
assertThat(results.getText().toString(), equalTo("Testing Android Rocks!"));
}
}
</pre>
@RunWith(RobolectricGradleTestRunner.class)
表示用Robolectric的TestRunner來跑這些test,通過gradle CLI或者Android studio運(yùn)行為單元測試定制的測試運(yùn)行程序幕帆,有一條件必須配置@Config
@RunWith(RobolectricTestRunner.class)
提供Android運(yùn)行時(shí)的模擬環(huán)境
Robolectric框架通過shadow類替換對應(yīng)的真實(shí)方法获搏,最終實(shí)現(xiàn)測試脫離底層實(shí)現(xiàn),感興趣的話失乾,可以自行了解
Mock
對于一些依賴關(guān)系復(fù)雜的測試對象常熙,可以采用Mock框架解除依賴,常用的有Mockito,mock創(chuàng)建一個(gè)類的虛假的對象碱茁,用于解耦真實(shí)對象所需要的依賴,Mock得到的對象僅僅是具備測試對象的類型裸卫,并不是真實(shí)的對象,也就是并沒有執(zhí)行過真實(shí)對象的邏輯早芭。
引入
repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:2.+" }
Mock的方法使用
// mock creation
List mockedList = mock(List.class);
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();
// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
直接通過mock方法創(chuàng)建虛擬對象彼城,也可以使用注解的方式 @Mock 來創(chuàng)建,通過 verify 方法來檢查相應(yīng)方法是否調(diào)用
stub形式的使用
// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");
// the following prints "first"
System.out.println(mockedList.get(0));
// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
指定關(guān)鍵字 when 返回一個(gè) OngoingStubbing 接口退个,通過其提供的 thenReturn募壕,thenThrow,thenCallRealMethod 及自定義 thenAnswer 來返回相應(yīng)的結(jié)果
Mock中幾個(gè)主要的方法
- mock()/@Mock: 創(chuàng)建一個(gè)Mock虛擬對象
- spy()/@Spy: 部分mock语盈,真正的方法會被調(diào)用舱馅,但是仍然需要驗(yàn)證
- verify(): 檢測方法是否被調(diào)用
通過 times,never刀荒,atLeastOnce代嗤,atLeast,atMost 這些方法缠借,我們可以對一個(gè)方法的調(diào)用次數(shù)做判斷
verify(mockedList, atLeastOnce()).add("three times")
通過doThrow為一個(gè)方法的調(diào)用添加異常干毅,驗(yàn)證代碼對異常的處理
doThrow(new RuntimeException()).when(mockedList).clear();
通過Mockito的inOrder方法驗(yàn)證調(diào)用順序
更多使用方法請參考mock官網(wǎng)
注:final類型、private類型以及靜態(tài)類型的方法不能mock
總結(jié)
JUnit框架主要是用來測試java類的泼返,既能做單元測試也能做集成測試硝逢,如果想要調(diào)用android的方法需要用到Robolectric框架,這兩個(gè)框架可以做的事情很多绅喉,幾乎能滿足你所有的需求渠鸽,但是有的時(shí)候測試需要用到虛擬對象,就需要用到Mock框架了柴罐。
希望這篇文章徽缚,對初次接觸單元測試的你有所幫助
參考文獻(xiàn):