既然認(rèn)為它是好的,就要發(fā)揮到極限-系列之二單元測(cè)試
既然測(cè)試是好的,那就把它發(fā)揮到極限。
測(cè)試是好的,這一點(diǎn)無可厚非,幾乎做軟件的人都是認(rèn)可的,本篇只是談?wù)劀y(cè)試中的單元測(cè)試部分,單元測(cè)試的目的是為了保證類中的方法是符合設(shè)計(jì)時(shí)的需求的,需求驅(qū)動(dòng)似的類實(shí)現(xiàn),^_^
單元測(cè)試的好處
1、保證類對(duì)于設(shè)計(jì)以及需求的符合
在沒有單元測(cè)試的情況下,其實(shí)是很難保證類對(duì)于設(shè)計(jì)以及需求的符合的,很多情況往往會(huì)因?yàn)殚_發(fā)人員本身的因素將實(shí)現(xiàn)代碼復(fù)雜化,并且編寫出很多設(shè)計(jì)和需求根本不需要的東西。
2、降低調(diào)試的復(fù)雜性
想想在沒有單元測(cè)試的情況下,調(diào)試通常是集成時(shí)才做的,這個(gè)時(shí)候要通過慢慢的跟蹤來查找問題的原因,而在web系統(tǒng)中就更痛苦了,總是要重啟,如果不想那么痛苦,就采用單元測(cè)試吧。
3、減少集成時(shí)出錯(cuò)的機(jī)率
單元測(cè)試可保證暴露給外部的API的正確性,減少要通過集成才發(fā)現(xiàn)錯(cuò)誤的現(xiàn)象。
4、保證重構(gòu)和簡(jiǎn)單設(shè)計(jì)的可行
想想,如果沒有單元測(cè)試,怎么敢對(duì)代碼做重構(gòu)呢,如果沒有單元測(cè)試,簡(jiǎn)單設(shè)計(jì)很難通過重構(gòu)去演變成為將來更好的設(shè)計(jì)。
單元測(cè)試的實(shí)現(xiàn)
單元測(cè)試的實(shí)現(xiàn)采取的方法通常是xUnit,在Java界就是junit了,最重要的仍然不是工具,而是怎么去實(shí)現(xiàn)單元測(cè)試的方法,測(cè)試驅(qū)動(dòng)開發(fā)無疑是最佳的編寫測(cè)試的方法,首先根據(jù)設(shè)計(jì)或需求編寫測(cè)試,根據(jù)測(cè)試編寫代碼,直到測(cè)試通過為止。
在代碼出現(xiàn)bug時(shí),一定要先把出現(xiàn)bug的情況補(bǔ)充到測(cè)試中去,接下來仍然是修改實(shí)現(xiàn)代碼,直到測(cè)試通過。
單元測(cè)試編寫的原則其實(shí)很簡(jiǎn)單,就是測(cè)試一定情況下類的執(zhí)行是否符合預(yù)期。
還是舉例來說:
假設(shè)需要編寫一個(gè)根據(jù)用戶名和密碼驗(yàn)證用戶的服務(wù),按照TDD我們首先編寫單元測(cè)試類,我們應(yīng)該怎么來編寫這個(gè)單元測(cè)試類呢,一般可按照一個(gè)這樣的步驟:
1、分析類的輸入。
這點(diǎn)通常是分析類依賴外部什么類,需要在測(cè)試類中提前注入。
以上面的服務(wù)來說,通常需要依賴的是用戶的Dao類。
2、分析方法的輸入造成的輸出的影響。
這點(diǎn)通常是分析方法輸入的參數(shù)對(duì)執(zhí)行結(jié)果造成的影響。
以上面的服務(wù)來說,輸入的參數(shù)為用戶名和密碼,這個(gè)時(shí)候會(huì)有幾種情況會(huì)出現(xiàn):
2.1 用戶名或密碼為null
在這種情況下,假設(shè)期待的輸出為false
2.2 用戶名和密碼都為null
在這種情況下,假設(shè)期待的輸出為false
2.3 輸入的用戶名和密碼在系統(tǒng)中存在
在這種情況下,假設(shè)期待的輸出為true
2.4 用戶名或密碼其中一項(xiàng)輸入不正確,驗(yàn)證不通過
在這種情況下,假設(shè)期待的拋出AuthronizedException
在經(jīng)過這樣的分析后,就可以開始編寫測(cè)試類了,編寫的測(cè)試類如下(示例代碼而已):

public class UserServiceTest extends TestCase
{

private UserDao dao=null;
private UserService service=null;
private User user=null;

public static void main(String[] args)
{
junit.textui.TestRunner.run(UserServiceTest.class);
}


protected void setUp() throws Exception
{
super.setUp();
dao=new UserDaoImpl();
user=new User();
user.setName("TEST_BLUEDAVY");
user.setPass("JERRY");
dao.save(user);
service=new UserServiceImpl();
service.setDao(dao);
}


protected void tearDown() throws Exception
{
super.tearDown();
dao.delete(user);
}

public void testWhenNameAndPassAreNull()
{
assertEquals(false,service.login(user.getName(),user.getPass()));
}


public void testWhenNameOrPassIsNull()
{
assertEquals(false,service.login(user.getName(),user.getPass()));
}

public void testWhenNameAndPassAreCorrect()
{
assertEquals(true,service.login(user.getName(),user.getPass()));
}

public void testWhenNameOrPassIsError()
{

try
{
service.login(user.getName(),user.getPass());
}

catch(Exception e)
{
assertEquals(AuthronizedException.class,e.getClass());
}
}
}
在編寫完測(cè)試類后就可以開始編寫實(shí)現(xiàn)代碼了,實(shí)現(xiàn)代碼在編寫的時(shí)候很簡(jiǎn)單,只要能夠保證測(cè)試通過就完事,在測(cè)試通過后可以開始考慮重構(gòu)的事,重構(gòu)仍然只要保證測(cè)試通過即可,其實(shí)這個(gè)時(shí)候就可以看到,簡(jiǎn)單設(shè)計(jì)就變得可行了,因?yàn)榭梢酝ㄟ^重構(gòu)來提升設(shè)計(jì)。
如果將來這段代碼出現(xiàn)bug,就把bug中的輸入情況也編寫為一個(gè)測(cè)試方法進(jìn)行測(cè)試,開始運(yùn)行就應(yīng)該和bug一樣出現(xiàn)問題,這時(shí)只需去修正實(shí)現(xiàn)代碼,直到測(cè)試通過為止,那么bug也就自然被修正了。
簡(jiǎn)單的單元測(cè)試的編寫較為簡(jiǎn)單,復(fù)雜的單元測(cè)試則可能需要使用Mock來模擬一些環(huán)境,Mock方面的工具有很多,大家可以去參考相關(guān)的開源工具的網(wǎng)站。
經(jīng)驗(yàn)總結(jié)
對(duì)于單元測(cè)試通常很多人都有疑問,執(zhí)行起來的時(shí)候經(jīng)常是不夠徹底,特別是在項(xiàng)目時(shí)間緊張的情況下,總是覺得編寫測(cè)試是一種耽誤時(shí)間的事,其實(shí)編寫單元測(cè)試會(huì)為你節(jié)省非常多的時(shí)間,想想我們大部分的項(xiàng)目都是在集成、修改bug和維護(hù)上消耗了大量的時(shí)間,既然單元測(cè)試這么好,那么我們就實(shí)現(xiàn)單元測(cè)試吧。
在單元測(cè)試中最重要的注意點(diǎn)就是不要依賴于正常的運(yùn)行數(shù)據(jù),所有的數(shù)據(jù)都要通過代碼模擬出來,在測(cè)試完畢后清除,避免造成測(cè)試對(duì)于運(yùn)行數(shù)據(jù)的依賴,同時(shí)也避免測(cè)試數(shù)據(jù)對(duì)于實(shí)際運(yùn)行系統(tǒng)的影響。
測(cè)試是好的,這一點(diǎn)無可厚非,幾乎做軟件的人都是認(rèn)可的,本篇只是談?wù)劀y(cè)試中的單元測(cè)試部分,單元測(cè)試的目的是為了保證類中的方法是符合設(shè)計(jì)時(shí)的需求的,需求驅(qū)動(dòng)似的類實(shí)現(xiàn),^_^
單元測(cè)試的好處
1、保證類對(duì)于設(shè)計(jì)以及需求的符合
在沒有單元測(cè)試的情況下,其實(shí)是很難保證類對(duì)于設(shè)計(jì)以及需求的符合的,很多情況往往會(huì)因?yàn)殚_發(fā)人員本身的因素將實(shí)現(xiàn)代碼復(fù)雜化,并且編寫出很多設(shè)計(jì)和需求根本不需要的東西。
2、降低調(diào)試的復(fù)雜性
想想在沒有單元測(cè)試的情況下,調(diào)試通常是集成時(shí)才做的,這個(gè)時(shí)候要通過慢慢的跟蹤來查找問題的原因,而在web系統(tǒng)中就更痛苦了,總是要重啟,如果不想那么痛苦,就采用單元測(cè)試吧。
3、減少集成時(shí)出錯(cuò)的機(jī)率
單元測(cè)試可保證暴露給外部的API的正確性,減少要通過集成才發(fā)現(xiàn)錯(cuò)誤的現(xiàn)象。
4、保證重構(gòu)和簡(jiǎn)單設(shè)計(jì)的可行
想想,如果沒有單元測(cè)試,怎么敢對(duì)代碼做重構(gòu)呢,如果沒有單元測(cè)試,簡(jiǎn)單設(shè)計(jì)很難通過重構(gòu)去演變成為將來更好的設(shè)計(jì)。
單元測(cè)試的實(shí)現(xiàn)
單元測(cè)試的實(shí)現(xiàn)采取的方法通常是xUnit,在Java界就是junit了,最重要的仍然不是工具,而是怎么去實(shí)現(xiàn)單元測(cè)試的方法,測(cè)試驅(qū)動(dòng)開發(fā)無疑是最佳的編寫測(cè)試的方法,首先根據(jù)設(shè)計(jì)或需求編寫測(cè)試,根據(jù)測(cè)試編寫代碼,直到測(cè)試通過為止。
在代碼出現(xiàn)bug時(shí),一定要先把出現(xiàn)bug的情況補(bǔ)充到測(cè)試中去,接下來仍然是修改實(shí)現(xiàn)代碼,直到測(cè)試通過。
單元測(cè)試編寫的原則其實(shí)很簡(jiǎn)單,就是測(cè)試一定情況下類的執(zhí)行是否符合預(yù)期。
還是舉例來說:
假設(shè)需要編寫一個(gè)根據(jù)用戶名和密碼驗(yàn)證用戶的服務(wù),按照TDD我們首先編寫單元測(cè)試類,我們應(yīng)該怎么來編寫這個(gè)單元測(cè)試類呢,一般可按照一個(gè)這樣的步驟:
1、分析類的輸入。
這點(diǎn)通常是分析類依賴外部什么類,需要在測(cè)試類中提前注入。
以上面的服務(wù)來說,通常需要依賴的是用戶的Dao類。
2、分析方法的輸入造成的輸出的影響。
這點(diǎn)通常是分析方法輸入的參數(shù)對(duì)執(zhí)行結(jié)果造成的影響。
以上面的服務(wù)來說,輸入的參數(shù)為用戶名和密碼,這個(gè)時(shí)候會(huì)有幾種情況會(huì)出現(xiàn):
2.1 用戶名或密碼為null
在這種情況下,假設(shè)期待的輸出為false
2.2 用戶名和密碼都為null
在這種情況下,假設(shè)期待的輸出為false
2.3 輸入的用戶名和密碼在系統(tǒng)中存在
在這種情況下,假設(shè)期待的輸出為true
2.4 用戶名或密碼其中一項(xiàng)輸入不正確,驗(yàn)證不通過
在這種情況下,假設(shè)期待的拋出AuthronizedException
在經(jīng)過這樣的分析后,就可以開始編寫測(cè)試類了,編寫的測(cè)試類如下(示例代碼而已):






































































在編寫完測(cè)試類后就可以開始編寫實(shí)現(xiàn)代碼了,實(shí)現(xiàn)代碼在編寫的時(shí)候很簡(jiǎn)單,只要能夠保證測(cè)試通過就完事,在測(cè)試通過后可以開始考慮重構(gòu)的事,重構(gòu)仍然只要保證測(cè)試通過即可,其實(shí)這個(gè)時(shí)候就可以看到,簡(jiǎn)單設(shè)計(jì)就變得可行了,因?yàn)榭梢酝ㄟ^重構(gòu)來提升設(shè)計(jì)。
如果將來這段代碼出現(xiàn)bug,就把bug中的輸入情況也編寫為一個(gè)測(cè)試方法進(jìn)行測(cè)試,開始運(yùn)行就應(yīng)該和bug一樣出現(xiàn)問題,這時(shí)只需去修正實(shí)現(xiàn)代碼,直到測(cè)試通過為止,那么bug也就自然被修正了。
簡(jiǎn)單的單元測(cè)試的編寫較為簡(jiǎn)單,復(fù)雜的單元測(cè)試則可能需要使用Mock來模擬一些環(huán)境,Mock方面的工具有很多,大家可以去參考相關(guān)的開源工具的網(wǎng)站。
經(jīng)驗(yàn)總結(jié)
對(duì)于單元測(cè)試通常很多人都有疑問,執(zhí)行起來的時(shí)候經(jīng)常是不夠徹底,特別是在項(xiàng)目時(shí)間緊張的情況下,總是覺得編寫測(cè)試是一種耽誤時(shí)間的事,其實(shí)編寫單元測(cè)試會(huì)為你節(jié)省非常多的時(shí)間,想想我們大部分的項(xiàng)目都是在集成、修改bug和維護(hù)上消耗了大量的時(shí)間,既然單元測(cè)試這么好,那么我們就實(shí)現(xiàn)單元測(cè)試吧。
在單元測(cè)試中最重要的注意點(diǎn)就是不要依賴于正常的運(yùn)行數(shù)據(jù),所有的數(shù)據(jù)都要通過代碼模擬出來,在測(cè)試完畢后清除,避免造成測(cè)試對(duì)于運(yùn)行數(shù)據(jù)的依賴,同時(shí)也避免測(cè)試數(shù)據(jù)對(duì)于實(shí)際運(yùn)行系統(tǒng)的影響。
posted on 2006-01-22 23:43 BlueDavy 閱讀(1934) 評(píng)論(3) 編輯 收藏 所屬分類: Java 、軟件工程