在做項目的時(shí)候,經(jīng)??匆?jiàn)很多兄弟們在做一些無(wú)用功,其實(shí),現在Java語(yǔ)言已經(jīng)形成了一個(gè)形形色色的生態(tài)圈,在這個(gè)生態(tài)圈里,有IT巨鱷的IBM,有兩頭受氣的Sun,還有各種各樣為我們提供工具的開(kāi)源社區,如Apache,eclipse,freshmeat,sourceforge,netbeans等。此外,J2SE 5.0推出以后也為我們節省了不少工作。我們完全可以利用這些資源,節省很多為老板干活的時(shí)間,從而將有限的生命投入到無(wú)限的泡MM事業(yè)中去。
閑言少敘,dingdang準備寫(xiě)個(gè)系列文章,講述一些工具,API以及其背后的原理。兄弟拋塊磚先,有玉的盡管砸過(guò)來(lái),我閃
一,測試工具EasyMock
在這個(gè)系列文章中以測試開(kāi)始,把它作為我們這篇入門(mén)介紹文檔的開(kāi)頭,不是偶然的,正如村上春樹(shù)在《挪威的森林》里面說(shuō)的那樣,死并不是生的對立面,而是作為生的一部分而存在。測試也不是開(kāi)發(fā)的對立面,而是作為開(kāi)發(fā)的一部分而存在,我們總是在不斷的寫(xiě)代碼,單元測試,寫(xiě)代碼,單元測試......作為單元測試的工具JUnit框架大家可能已經(jīng)耳熟能詳,Martin Fowler對它的評價(jià)是"Never in the field of software development was so much owed by so many to so few lines of code"。一時(shí)AUnit,BUnit,仿效者無(wú)數??芍^武林至尊
可是,僅僅JUnit是不夠的。我們在做項目的時(shí)候就遇到了這樣的場(chǎng)景:
大米:終于寫(xiě)完代碼了,可以上QQ泡MM了.....
dingdang:哦,寫(xiě)完了,給個(gè)測試用例先。
大米:沒(méi)法子給測試用例啊,我寫(xiě)的這個(gè)類(lèi)要用到苞谷寫(xiě)的類(lèi)耶
dingdang去找苞谷:苞谷,你的代碼怎么還沒(méi)寫(xiě)完啊,搞的大米連單元測試都做不了。
苞谷:不是我得錯,蘋(píng)果沒(méi)有寫(xiě)完我需要的類(lèi)
蘋(píng)果:也不是我得錯,大米沒(méi)有寫(xiě)完我需要的類(lèi)
dingdang:×※……%¥
其實(shí),這些類(lèi)的依賴(lài)關(guān)系首先是違反了一個(gè)原則:The Dependency Inversion Principle(依賴(lài)轉置原則)
抽象不應該依賴(lài)于細節,而細節應該依賴(lài)于抽象。
高層的模塊不應該依賴(lài)于底層的模塊,它們都應該依賴(lài)于抽象
通俗一點(diǎn)的說(shuō),就是,我們在做Java設計的時(shí)候,應該盡可能的依賴(lài)于接口而不是實(shí)現。
dingdang嘿嘿奸笑兩聲:大米啊,我們修改一下設計吧,把我們的設計refactoring一下。
三分鐘后,大米說(shuō):dingdang啊,改成接口還是沒(méi)法子測試啊。
dingdang再次狂笑:哈哈,倚天不出,誰(shuí)與爭鋒,看我的easymock!!!!!
easymock軟件安裝很簡(jiǎn)單,先到以下地址下載一個(gè)最新的zip包:
www.easymock.org,下載完以后將easymock.jar包加到你的系統的CLASSPATH環(huán)境變量中,對于IDE環(huán)境,對于需要用到的junit的項目增加到lib中,不同的IDE有不同的設置,這里不多講。
easymock的長(cháng)處在于模擬接口的行為,(新版的easymock利用cglib據說(shuō)也可以模擬類(lèi)的行為,沒(méi)有試用過(guò):P)假如你有一個(gè)類(lèi)HelloWorld,依賴(lài)接口DependentInterface,easymock就可以在運行的時(shí)候生成DependentInterface接口的實(shí)現。這些實(shí)現的行為和返回值都可以在單元測試代碼里面指定。我們用一個(gè)JUnit例子來(lái)進(jìn)行說(shuō)明
首先,需要導入MockControl類(lèi),如下樣例中的第一步,
然后選擇一個(gè)接口,創(chuàng )建這個(gè)接口的模擬實(shí)例,如以下樣例中的第二步。
最后,先模擬一下你希望的類(lèi)的行為,如返回值等,調用MockControl類(lèi)的replay方法:
import junit.framework.*;
import org.easymock.MockControl;// step 1
interface DependentInterface{
public String sayHello();
}
class HelloWorld{
private DependentInterface dp_;
public HelloWorld(DependentInterface dp){
dp_ = dp;
}
public String sayAnotherHello(){
return dp_.sayHello();
}
}
public class TestHelloWorld extends TestCase {
private HelloWorld helloWorld_ = null;
private MockControl control_;
private DependentInterface dp_;
protected void setUp() throws Exception {
super.setUp();
control_ = MockControl.createControl(DependentInterface.class);//step 2
dp_ =(DependentInterface)control_.getMock();//step 2
helloWorld_ = new HelloWorld(dp_);
}
protected void tearDown() throws Exception {
helloWorld_ = null;
super.tearDown();
}
public void testSayHello() {
dp_.sayHello();//step 3
control_.setReturnValue("hello");//step 3
control_.replay();//step 3
String actualReturn = helloWorld_.sayAnotherHello();
assertEquals(actualReturn,"hello");
}
}
easymock本身的文檔寫(xiě)得很好,大家看看就會(huì )了,最重要的是依賴(lài)轉置的思想和測試驅動(dòng)的方法。
dingdang爭取下一篇文章剖析easymock的源代碼,解釋Java的Dynamic Proxy的原理