隨筆 2019年8月26日
單元測試
什么是單元測試
單元測試是對軟件或程序的基本(最?。┙M成。
特點:
- 可重復執(zhí)行
- 執(zhí)行速度快
- 獨立無依賴
- 結(jié)果不改變
為什么要寫單元測試
- 使我們更了解需求
- 快速驗證
- 使重構(gòu)更容易
- 更早了解程序的問題
Junit
例子
import org.junit.*;
import static org.junit.Assert.fail;
public class ClassNameTest {
@BeforeClass //公開表態(tài)無返回值
public static void beforeClass() throws Exception{
//每次測試類執(zhí)行前執(zhí)行一次,主要用來初使化公共資源等
}
@AfterClass //公開表態(tài)無返回值
public static void afterClass() throws Exception{
//每次測試類執(zhí)行完成后執(zhí)行一次,主要用來釋放資源或清理工作
}
@Before
public void setup() throws Exception {
//每個測試案例執(zhí)行前都會執(zhí)行一次
}
@After
public void teardown() throws Exception {
//每個測試案例執(zhí)行完成后都會執(zhí)行一次
}
@Test
public void testMethodName_give_…_when_…_then_…() {
fail("失敗");
}
}
常用的注解
-
@Ignore
該注解標記的測試方法在測試中會被忽略。
-
@Test
@Test(expected=xxxException.class) 斷言該方法會拋出異常
@Test(timeout=1000) 執(zhí)行時間超過設(shè)置的值該案例會失敗 -
@RunWith
@RunWith(Suite.class) 測試集運行器配合使用測試集功能
@RunWith(JUnit4.class) 默認運行器
@RunWith(Parameterized.class) 參數(shù)化運行器 -
@Before
初始化方法,在任何一個測試方法執(zhí)行之前,必須執(zhí)行的代碼。對比 JUnit 3 ,和 setUp()方法具有相同的功能。在該注解的方法中,可以進行一些準備工作,比如初始化對象,打開網(wǎng)絡(luò)連接等。
-
@After
釋放資源,在任何一個測試方法執(zhí)行之后,需要進行的收尾工作。對比 JUnit 3 ,和 tearDown()方法具有相同的功能。
-
@BeforeClass
針對所有測試,也就是整個測試類中,在所有測試方法執(zhí)行前,都會先執(zhí)行由它注解的方法,而且只執(zhí)行一次。當然,需要注意的是,修飾符必須是 public static void xxxx ;此 Annotation 是 JUnit 4 新增的功能。
-
@AfterClass
針對所有測試,也就是整個測試類中,在所有測試方法都執(zhí)行完之后,才會執(zhí)行由它注解的方法,而且只執(zhí)行一次。當然,需要注意的是,修飾符也必須是 public static void xxxx ;此 Annotation 也是 JUnit 4 新增的功能,與 @BeforeClass 是一對。
斷言
常用的斷言方法如下:
assertEquals(a, b)
測試a是否等于b(a和b是原始類型數(shù)值(primitive value)或者必須為實現(xiàn)比較而具有equal方法)assertFalse(a)
測試a是否為false(假),a是一個Boolean數(shù)值。assertTrue(a)
測試a是否為true(真),a是一個Boolean數(shù)值assertNotNull(a)
測試a是否非空,a是一個對象或者null。assertNull(a)
測試a是否為null,a是一個對象或者null。assertNotSame(a, b)
測試a和b是否沒有都引用同一個對象。assertSame(a, b)
測試a和b是否都引用同一個對象。fail(string)
Fail讓測試失敗,并給出指定信息。assertThat(expected, Matcher)
通過Matcher斷言
執(zhí)行順序
在 JUnit 4 中,單元測試用例的執(zhí)行順序為:
@Before → @Before → @Test → @After → @AfterClass
建議
要寫注釋,建議分為如下4步驟。
- 測試場景
- 準備數(shù)據(jù)
- 測試執(zhí)行
- 斷言
Mock
前言
為什么需要Mock或Stub?它與Junit什么關(guān)系?
在做單元測試的時候,我們會發(fā)現(xiàn)我們要測試的方法會引用很多外部依賴的對象。 而我們沒法控制這些外部依賴的對象。為了解決這個問題,我們需要用到Stub和Mock來模擬這些外部依賴的對象,從而控制它們。
JUnit是單元測試框架,可以輕松的完成關(guān)聯(lián)依賴關(guān)系少或者比較簡單的類的單元測試,但是對于關(guān)聯(lián)到其它比較復雜的類或?qū)\行環(huán)境有要求的類的單元測試,模擬環(huán)境或者配置環(huán)境會非常耗時,實施單元測試比較困難。而這些Mock框架(Mockito 、jmock 、 powermock、EasyMock),可以通過mock框架模擬一個對象的行為,從而隔離開我們不關(guān)心的其他對象,使得測試變得簡單。
例如: service調(diào)用dao,即service依賴dao,我們可以通過mock dao來模擬真實的dao調(diào)用,從而能達到測試service的目的。
模擬對象(Mock Object)可以取代真實對象的位置,用于測試一些與真實對象進行交互或依賴于真實對象的功能,模擬對象的背后目的就是創(chuàng)建一個輕量級的、可控制的對象來代替測試中需要的真實對象,模擬真實對象的行為和功能。
Mock與Stub什么區(qū)別?
Mock和Stub是兩種測試代碼功能的方法。Mock測重于對功能的模擬,Stub測重于對功能的測試重現(xiàn)。比如對于List接口,Mock會直接對List進行模擬,而Stub會新建一個實現(xiàn)了List的TestList,在其中編寫測試的代碼。
強烈建議優(yōu)先選擇Mock方式,因為Mock方式下,模擬代碼與測試代碼放在一起,易讀性好,而且擴展性、靈活性都比Stub好。
其中EasyMock和Mockito對于Java接口使用接口代理的方式來模擬,對于Java類使用繼承的方式來模擬(也即會創(chuàng)建一個新的Class類)。Mockito支持spy方式,可以對實例進行模擬。但它們都不能對靜態(tài)方法和final類進行模擬,powermock通過修改字節(jié)碼來支持了此功能。