主要內(nèi)容:
● 概述單元測試相關(guān)概念及意義
● TestNG膀藐、Mockito、Unitils測試框架簡介
● 使用TestNG、Mockito落君、Unitils及Spring進行單元測試
● 面向數(shù)據(jù)庫應(yīng)用的測試
1.概述單元測試
按照軟件工程思想,軟件測試可以分為單元測試亭引、集成測試绎速、功能測試、系統(tǒng)測試焙蚓。功能測試和系統(tǒng)測試一般來說是測試人員的職責(zé)纹冤,但單元測試和集成測試則必須由開發(fā)人員保證。
1.1為什么需要單元測試购公?
軟件測試階段通過人工或自動手動來運行或測試某個系統(tǒng)的過程萌京,目的在于檢驗它是否滿足規(guī)定的需求或弄清楚預(yù)期結(jié)果與實際結(jié)果的差別。
單元測試
單元測試是開發(fā)者編寫的一小段代碼宏浩,用于檢驗?zāi)繕?biāo)代碼的一個很小的知残、很明確的功能是否正確。一個單元測試通常用于判斷某個特定條件或特定場景下某個特定函數(shù)的行為绘闷。例如:用戶可能把一個很大的值放入一個有序的List中橡庞,然后確認該值出現(xiàn)在List的尾部较坛。
程序員有責(zé)任編寫功能代碼,同時也有責(zé)任為自己的代碼編寫單元測試扒最。執(zhí)行單元測試丑勤,就是為了證明這段代碼的行為和我們期望的一致。
一般情況下吧趣,一個功能模塊往往會調(diào)用其他功能模塊來完成某項功能法竞,如業(yè)務(wù)層的業(yè)務(wù)類可能會調(diào)用多個DAO來完成某項業(yè)務(wù)。對某個功能模塊進行單元測試時强挫,我們希望拼比對外在功能模塊的依賴岔霸,以便將焦點放在目標(biāo)功能模塊的測試上。這時俯渤,模擬對象是最有力的工具呆细,它根據(jù)外在模塊的接口模擬特定的操作行為,這樣單元測試就可以在假設(shè)關(guān)聯(lián)模塊正確工作的情況下驗證本模塊的邏輯正確性八匠。
集成測試
集成測試在功能模塊開發(fā)完成后絮爷,為驗證功能模塊之間匹配調(diào)用的正確性而進行的測試。如:當(dāng)對UserService業(yè)務(wù)層的類進行單元測試時梨树,可以通過創(chuàng)建UserDao和LoginLogDao模擬對象坑夯,在假設(shè)DAO類正確工作的情況下對UserService進行測試。而對UserService進行集成測試時抡四,應(yīng)注入真實的UserDao和LoginLogDao進行測試柜蜈。
1.2.單元測試的好處
- 軟件質(zhì)量最簡單、最有效的保證指巡。
- 是目標(biāo)代碼最清晰淑履、最有效的文檔。
- 可以優(yōu)化目標(biāo)代碼的設(shè)計藻雪。
- 是代碼重構(gòu)的保障鳖谈。
1.3 單元測試的誤解
- 影響開發(fā)進度
- 增加開發(fā)成本
- 我是個編程高手,無需進行單元測試
- 測試人員會測出所有的bug
2.TestNG快速進階
編寫一個測試的過程由3個典型步驟阔涉。
1.編寫測試的業(yè)務(wù)邏輯并在代碼中插入TestNG注解
2.將測試信息添加到testng.xml或者build.xml文件中
3.運行TestNG
2.1TestNG生命周期
完整生命周期:類級初始化資源處理、方法級初始化資源處理捷绒、執(zhí)行測試用例中的方法瑰排、方法級銷毀資源處理、類級銷毀資源處理暖侨。
類級初始化椭住、銷毀資源處理方法在一個測試用例類中只能運行一次;
方法級初始化字逗、銷毀資源處理方法在執(zhí)行測試用例的每個測試方法中都會運行一次京郑,以防止測試方法相互之間的影響宅广。
如果在一個測試用例中編寫了多個初始化處理方法,則運行時先執(zhí)行位于最后面的初始化方法些举,然后往前一個個執(zhí)行初始化方法跟狱。對于多個銷毀資源處理方法,則按照方法的順序一個個往后執(zhí)行户魏。
2.2使用TestNG
1.測試方法
使用@Test注解來標(biāo)注一個測試方法驶臊。此外可以引用Java5.0的靜態(tài)導(dǎo)入功能導(dǎo)入斷言Assert類,方便地在測試方法中使用斷言方法叼丑。
public class TestNGTest {
private Car audi;
private Car benz;
private Car bmw;
@BeforeMethod
protected void setUp() {
audi = new Car("yellow","audi",180);
benz = new Car("white","benz",220);
bmw = new Car("black","bmw",190);
}
@Test
private void getBean() {
Assert.assertEquals("audi", audi.getBrand());
}
}
在TestNG中关翎,在測試方法添加@Test注解即可。
@BeforeClass @AfterClass 在一個Test類的所有測試方法執(zhí)行前后各執(zhí)行一次
@BeforeClass/@AfterClass | @BeforeMethod/@AfterMethod |
---|---|
在一個類中只能出現(xiàn)一次 | 在一個類可出現(xiàn)多次鸠信,執(zhí)行順序不確定 |
方法名不限制 | 方法名不限制 |
類中只執(zhí)行一次 | 在每個測試方法之前或者之后都會執(zhí)行一次 |
@BeforeClass父類中標(biāo)識了該注解的方法將會先于當(dāng)前類中標(biāo)識了該注解的方法執(zhí)行纵寝。 @AfterClass父類中標(biāo)識了該注解的方法將會在當(dāng)前類中標(biāo)識了該注解的方法之后執(zhí)行。 |
@BeforeMethod父類中標(biāo)識了該注解的方法將會先于當(dāng)前類中標(biāo)識了該注解的方法執(zhí)行星立。 @AfterMethod父類中標(biāo)識了該注解的方法將會在當(dāng)前類中標(biāo)識了該注解的方法之后執(zhí)行爽茴。 |
必須聲明為public static | 必須聲明為public,并且非static |
所有標(biāo)識為@AfterClass的方法一定會被執(zhí)行贞铣,即使標(biāo)識為@BeforeClass的方法拋出異常的情況下也會執(zhí)行 | 所有標(biāo)識為@AfterMethod的方法一定會被執(zhí)行闹啦,即使標(biāo)識為@BeforeMethod或@Test的方法拋出異常的情況下也會執(zhí)行 |
2.異常測試
通過對@Test傳入expected參數(shù)值,即可測試異常辕坝。3.超時測試
通過對@Test注解中為timeOut參數(shù)指定時間值窍奋,即可進行超時測試。
如果測試運行時間超過指定的毫秒數(shù)酱畅,即測試失敗琳袄。超時測試對網(wǎng)路鏈接類非常重要。
4.參數(shù)化測試
為了測試程序的健壯性纺酸,可能需要模擬不同的參數(shù)對方法進行測試窖逗。如果每個類型的參數(shù)創(chuàng)建一個測試方法,很難接受餐蔬。TestNG提供參數(shù)化測試碎紊。
package sample.testng;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import static org.testng.Assert.*;
import org.testng.annotations.*;
public class TestNGParameterTest {
private SimpleDateFormat simpleDateFormat;
@DataProvider(name = "testParam")
public static Object[][] getParamters() {
String[][] params = {
{ "2016-02-01 00:30:59", "yyyyMMdd", "20160201" },
{ "2016-02-01 00:30:59", "yyyy年MM月dd日", "2016年02月01日" },
{ "2016-02-01 00:30:59", "HH時mm分ss秒", "00時30分59秒" } };
return params;
}
@Test(dataProvider = "testParam")
public void testSimpleDateFormat(String date,String dateformat,String expectedDate) throws ParseException{
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = df.parse(date);
simpleDateFormat = new SimpleDateFormat(dateformat);
String result = simpleDateFormat.format(d);
assertEquals(result,expectedDate);
}
}
首先編寫測試類的參數(shù)數(shù)據(jù)提供者方法,然后用此方法進行參數(shù)初始化樊诺。該方法返回一個Object[][]類型仗考。用@DataProvider注解標(biāo)識該方法并設(shè)置name。之后在需要測試的方法中設(shè)置@Test(dataProvider="")屬性词爬。
5.分組測試
TestNG支持執(zhí)行復(fù)雜的分組測試秃嗜。
@Test(groups = {"class-group"})
public class TestNGGroupsTest {
@Test(groups = {"group1", "group2"})
public void testMethod1() {
}
@Test(groups = {"group1", "group2"})
public void testMethod2() {
}
@Test(groups = {"group1"})
public void testMethod3() {
}
}
6.依賴測試
如果測試方法需要按照一個特定的順序被調(diào)用。TestNG為@Test注解提供了dependsOnMethods或dependsOnGroups屬性來實現(xiàn)測試方法間的依賴關(guān)系。
public class TestNGDependsTest {
@Test
public void testMethod1() {
}
@Test
public void testMethod2() {
assertNotNull(new User());
}
@Test(dependsOnMethods = {"testMethod1","testMethod2"},alwaysRun=true)
public void testMethod3() {
}
}
當(dāng)執(zhí)行testMethod3()測試方法時锅锨,會先調(diào)用兩個依賴的測試方法叽赊。如果testMethod1()或testMethod2()任意一個失敗都不會執(zhí)行testMethod3()。這種依賴為強依賴必搞,默認必指。可以通過@Test的alwaysRun=true改變顾画,則testMethod3()總會執(zhí)行取劫。