一、開胃示例
被測(cè)試類——獲取學(xué)生數(shù)據(jù):
/**
* 學(xué)生信息實(shí)體
*/
public class EStudent{
String name;
int age;
// 一堆getter、setter
/**
* 注意:自定義類時(shí)要重寫equals方法,否則默認(rèn)equals方法會(huì)使用==方式來(lái)比較對(duì)象的內(nèi)存地址是否相同裳瘪,而不是內(nèi)容是否相同。
*/
@Override
public boolean equals(Object obj){
if (obj == null || obl.getClass() != this.getClass()) return false;
EStudent other = (EStudent)obj;
if (!this.getName().equals(other.getName())
|| this.getAge() != other.getAge()) return false;
return true;
}
}
/**
* 學(xué)生數(shù)據(jù)操作接口
*/
public interface StudentDao{
public EStudent getStudent(int id);
}
/**
* 真實(shí)的數(shù)據(jù)操作類
*/
public class StudentDaoImpl
implements StudentDao{
public EStudent getStudent(int id){
EStudent ret = new EStudent();
ret.setName("fsjohnhuang");
ret.setAge(18);
return ret;
}
}
/**
* 模擬的數(shù)據(jù)操作類
*/
public class MockStudentDaoImpl
implements StudentDao{
public EStudent getStudent(int id){
EStudent ret = new EStudent();
ret.setName("fsjohnhuang");
ret.setAge(18);
return ret;
}
}
測(cè)試用例:
/**
* 由于下面采用參數(shù)化測(cè)試罪针,因此將測(cè)試運(yùn)行器更換為Parameterized
*/
@RunWith(Parameterized.class)
public class TestStudentDao{
static StudentDao dao, mockDao;
/**
* 執(zhí)行測(cè)試類中所有測(cè)試前執(zhí)行一次
* 用于前提條件的初始化
*/
@BeforeClass
public static void init(){
dao = new StudentDaoImpl();
mockDao = new MockStudentDaoImpl();
}
/**
* 接收測(cè)試用數(shù)據(jù)
*/
int id;
public TestStudentDao(int id){
this.id = id;
}
/**
* 測(cè)試用例
*/
@Test
public void testGetStudent(){
assertEquals("獲取學(xué)生信息", mockDao.getStudent(id), dao.getStudent(id));
}
/**
* 測(cè)試用數(shù)據(jù)提供方法
*/
@Parameters
public Collection dataFeed(){
return Arrays.asList(new Object[][]{{1},{2},{3}});
}
}
二彭羹、固件測(cè)試
就是每個(gè)測(cè)試方法執(zhí)行前和后都執(zhí)行的方法,用于自動(dòng)初始化和回收資源等工作泪酱。通過(guò) @Before 注解標(biāo)注測(cè)試方法執(zhí)行前調(diào)用的固件測(cè)試派殷,通過(guò) @After 注解標(biāo)注測(cè)試方法執(zhí)行后調(diào)用的固件測(cè)試。
父類的固件測(cè)試會(huì)在子類的固件測(cè)試前被調(diào)用墓阀。
另外可通過(guò)注解 @BeforeClass 和 @AfterClass 標(biāo)注某些static方法為測(cè)試開始前和結(jié)束后被調(diào)用毡惜,用于自動(dòng)初始化和回收資源等工作。注意通過(guò)注解 @BeforeClass 和 @AfterClass 標(biāo)注的方法一次測(cè)試過(guò)程僅被調(diào)用一次而已斯撮。
示例如下:
public class MyUT{
int i, j;
@BeforeClass public void static init(){
System.out.println("init");
i = 0;
j = 0;
}
@Before public void invokeBefore(){
System.out.println("invokeBefore" + ++i);
}
@Test public void testMyMethod1(){
System.out.println("testMyMethod1");
}
@Test public void testMyMethod2(){
System.out.println("testMyMethod2");
}
@After public void invokeAfter(){
System.out.println("invokeAfter" + ++j);
}
@AfterClass public void static destroy(){
System.out.println("destroy");
i = 0;
j = 0;
}
}
// 輸出結(jié)果
init
invokeBefore1
testMyMethod1
invokeAfter1
invokeBefore2
testMyMethod2
invokeAfter2
destroy
三经伙、忽略測(cè)試用例
通過(guò)注解 @Ignore() 可以標(biāo)注不參與測(cè)試的測(cè)試方法。當(dāng)然也可以通過(guò)去除注解 @Test 來(lái)達(dá)到這個(gè)目的勿锅,但去除注解 @Test 會(huì)令到eclipse的JUnit View中無(wú)法顯示該測(cè)試方法帕膜。
四、異常測(cè)試
通過(guò)注解 @Test(expected=Class類型) 來(lái)標(biāo)注期待測(cè)試方法執(zhí)行時(shí)拋出哪種異常對(duì)象溢十,若測(cè)試方法不拋出異晨迳玻或異常對(duì)象與期待的異常對(duì)象不相同則測(cè)試失敗。
@Test(expected=ArithmeticException.class)
public void calc(){
int i = 1/0;
}
五张弛、超時(shí)測(cè)試
通過(guò)注解 @Test(timeout=毫秒數(shù)) 來(lái)標(biāo)注期待執(zhí)行測(cè)試方法的最大耗時(shí)危纫,若超時(shí)則測(cè)試失敗。
@Test(timeout=1000)
public void wait(){
while(true){}
}
六乌庶、測(cè)試運(yùn)行器
用于執(zhí)行JUnit中所有的測(cè)試方法。JUnit為單元測(cè)試提供默認(rèn)的測(cè)試運(yùn)行器契耿,但我們可以自定義瞒大,自定義的測(cè)試運(yùn)行器必須繼承 org.junit.runner.Runner 。然后通過(guò)類注解 @RunWith(CustomTestRunner.class) 來(lái)指定該測(cè)試的測(cè)試運(yùn)行器搪桂。
常用的內(nèi)置測(cè)試運(yùn)行器:
1. org.junit.runners.Suite 透敌,套件測(cè)試時(shí)使用盯滚。
2. org.junit.runners.Parameterized ,參數(shù)化測(cè)試時(shí)使用酗电。
七魄藕、參數(shù)化測(cè)試
就是第一節(jié)中的測(cè)試類型,用于模擬以不同的參數(shù)組合來(lái)對(duì)方法進(jìn)行多次測(cè)試撵术。若不使用參數(shù)化測(cè)試背率,該測(cè)試方法有N個(gè)不同的參數(shù)組合,則需要寫N個(gè)測(cè)試方法來(lái)測(cè)試嫩与。
// 需要使用Parameterized測(cè)試運(yùn)行器才可以
@RunWith(Parameterized.class)
public class MyUT{
// 成員變量寝姿,用于存放測(cè)試用數(shù)據(jù)和測(cè)試期望值
int orig;
int expected;
public MyUT(int orig, int expected){
this.orig = orig;
this.expected = expected;
}
@Test public void testMyMethod(){
assertEquals(expected, orig + 1);
}
/**
* 測(cè)試數(shù)據(jù)和測(cè)試期望值的提供方法
* 必須用注解@Parameters標(biāo)注
* 必須返回Collection類型數(shù)據(jù)
*/
@Parameters public Collection dataFeed(){
return Arrays.asList(new Object[][]{
{1, 2},
{2, 3},
{3, 4}
});
}
}
八、套件測(cè)試
JUnit4去除JUnit3中套件測(cè)試注解划滋,而是通過(guò)另一形式提供套件測(cè)試饵筑。
套件測(cè)試就是按業(yè)務(wù)邏輯將測(cè)試類進(jìn)行分組,并以組為單位執(zhí)行單元測(cè)試处坪。
// 測(cè)試類1
public class MyUT1{
@Test public void testMyMehthod1(){
assertEquals(1,1);
}
}
// 測(cè)試類2
public class MyUT2{
@Test public void testMyMehthod2(){
assertEquals(2,2);
}
}
// 套件測(cè)試類
@RunWith(Suite.class)
@SuiteClass({MyUT1.class, MyUT2.class})
public class SuiteTest{
// 必須有一個(gè)public根资,無(wú)參數(shù)的構(gòu)造函數(shù)。使用默認(rèn)的構(gòu)造函數(shù)也可以
public SuiteTest(){}
}
九同窘、JUnit4.4的 assertThat斷言
JUnit4.4內(nèi)置Hamcrest測(cè)試組件的部分內(nèi)容玄帕,而 assertThat斷言 就是配置Hamcrest測(cè)試組件的匹配符來(lái)實(shí)現(xiàn)所有測(cè)試工作。由于Hamcrest的匹配符貼近自然語(yǔ)言塞椎,因此意思表達(dá)更明確桨仿。(JUnit4.4前的版本則需要引入hamcrest-core.jar和hamcrest-library.jar了)。
/* assertThat語(yǔ)法
* assertThat(T actual, Matcher<T> matcher);
* assertThat(String reason, T actual, Matcher<T> matcher);
* 入?yún)ctual為實(shí)際值案狠,入?yún)atcher為期待值的匹配符
*/
//測(cè)試變量是否大于指定值
assertThat(1, greaterThan(50));
//測(cè)試變量是否小于指定值
assertThat(1, lessThan(100));
//測(cè)試變量是否大于等于指定值
assertThat(1, greaterThanOrEqualTo(50));
//測(cè)試變量是否小于等于指定值
assertThat(1, lessThanOrEqualTo(100));
//測(cè)試所有條件必須成立
assertThat(1, allOf(greaterThan(50),lessThan(100)));
//測(cè)試只要有一個(gè)條件成立
assertThat(1, anyOf(greaterThanOrEqualTo(50), lessThanOrEqualTo(100)));
//測(cè)試無(wú)論什么條件成立(還沒(méi)明白這個(gè)到底是什么意思)
assertThat(1, anything());
//測(cè)試變量值等于指定值
assertThat(1, is(100));
//測(cè)試變量不等于指定值
assertThat(1, not(50));
/**字符串**/
String url = "http://www.taobao.com";
//測(cè)試變量是否包含指定字符
assertThat(url, containsString("taobao"));
//測(cè)試變量是否已指定字符串開頭
assertThat(url, startsWith("http://"));
//測(cè)試變量是否以指定字符串結(jié)尾
assertThat(url, endsWith(".com"));
//測(cè)試變量是否等于指定字符串
assertThat(url, equalTo("http://www.taobao.com"));
//測(cè)試變量再忽略大小寫的情況下是否等于指定字符串
assertThat(url, equalToIgnoringCase("http://www.taobao.com"));
//測(cè)試變量再忽略頭尾任意空格的情況下是否等于指定字符串
assertThat(url, equalToIgnoringWhiteSpace("http://www.taobao.com"));
/**集合**/
List<User> user = new ArrayList<User>();
user.add(test1);
user.add(test2);
//測(cè)試集合中是否還有指定元素
assertThat(user, hasItem(test1));
assertThat(user, hasItem(test2));
/**Map匹配**/
Map<String,User> userMap = new HashMap<String,User>();
userMap.put(test1.getUsername(), test1);
userMap.put(test2.getUsername(), test2);
//測(cè)試map中是否還有指定鍵值對(duì)
assertThat(userMap, hasEntry(test1.getUsername(), test1));
//測(cè)試map中是否還有指定鍵
assertThat(userMap, hasKey(test2.getUsername()));
//測(cè)試map中是否還有指定值
assertThat(userMap, hasValue(test2));
十服傍、 assumeThat假設(shè)斷言
位于 org.junit.Assume類 下,同樣是屬于Hamcrest組件的骂铁。用于假設(shè)當(dāng)條件成立時(shí)才會(huì)執(zhí)行后續(xù)的代碼吹零,條件不成立時(shí)是不會(huì)影響測(cè)試結(jié)果。
assumeThat(1, is(0));
System.out.println("I'm here"); // 這句不會(huì)被執(zhí)