不管是測試驅(qū)動開發(fā)或者是其它的開發(fā)模式,都會需要對代碼進行單元測試,對于關聯(lián)依賴關系少或者比較簡單的類來說,直接使用JUnit就可以輕松的完成測試工作,但是對于關聯(lián)到其它比較復雜的類或?qū)\行環(huán)境有要求的類的單元測試,比如ejb,servlet或Dao等,測試起來或者需要配置特定的環(huán)境,或者十分耗時,給單元測試造成困難。在這里介紹使用JMock來模擬那些不需要測試的類,幫助完成有單元測試。
例如,有這樣兩個類,一個是Dao.java,用于數(shù)據(jù)庫訪問成操作的,一個是Business.java,需要調(diào)用Dao進行業(yè)務處理。Dao.java是已經(jīng)在有數(shù)據(jù)庫的環(huán)境測試通過的,現(xiàn)在需要測試Business.java。通常情況下,我們需要在測試環(huán)境配置好數(shù)據(jù)庫連接環(huán)境,并且需要準備數(shù)據(jù)后,才可以開始Business.java的測試,現(xiàn)在如果通過JMock就可以不配置數(shù)據(jù)庫環(huán)境,也可以完成測試。
//Dao.java
package com.raistlin.test.jmock
public class Dao
{
public Dao()
{
}
public List execute(String sql)
{
//數(shù)據(jù)庫操作...
}
}
//Business.java
package com.raistlin.test.jmock
public class Business
{
private Dao dao ;
public void setDao(Dao dao)
{
this.dao = dao;
}
public String operate()
{
List list = dao.execute("select * from tbl_test");
return (String) list.get(0);
}
}
//BusinessTest.java
package com.raistlin.test.jmock
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.cglib.Mock;
public class BusinessTest extends MockObjectTestCase
{
private Mock mockDao = null;
private Business business = null;
protected void setUp() throws Exception
{
super.setUp();
mockDao = new Mock(Dao.class);
business = new Business();
}
protected void tearDown() throws Exception
{
mockDao = null;
business = null;
super.tearDown();
}
public void testOperate()
{
ArrayList stubList = new ArrayList();
stubList.add("test\");
// 定義Mock劇本
mockDao.expects(once())// 期待次數(shù)
.method//Dao.java
package com.raistlin.test.jmock
public class Dao
{
public Dao()
{
}public List execute(String sql)
{
//數(shù)據(jù)庫操作...
}
}
//Business.java
package com.raistlin.test.jmock
public class Business
{
private Dao dao ;
public void setDao(Dao dao)
{
this.dao = dao;
}
public String operate()
{
List list = dao.execute("select * from tbl_test");
return (String) list.get(0);
}
}
//BusinessTest.java
package com.raistlin.test.jmock
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.cglib.Mock;
public class BusinessTest extends MockObjectTestCase
{
private Mock mockDao = null;
private Business business = null;
protected void setUp() throws Exception
{
super.setUp();
mockDao = new Mock(Dao.class);
business = new Business();
}
protected void tearDown() throws Exception
{
mockDao = null;
business = null;
super.tearDown();
}
public void testOperate()
{
ArrayList stubList = new ArrayList();
stubList.add("test");
// 定義Mock劇本
mockDao.expects(once())// 期待次數(shù)
.method("execute")// 調(diào)用方法
.with(eq("select * from tbl_test"))// 傳入?yún)?shù)等于
.will(this.returnValue(stubList));// 返回對象
Dao dao = (Dao) mockDao.proxy();
business.setDao(dao);
assertEquals(business.operate(), "test");
}
}
("execute")// 調(diào)用方法
.with(eq("select * from tbl_test"))// 傳入?yún)?shù)等于
.will(this.returnValue(stubList));// 返回對象
Dao dao = (Dao) mockDao.proxy();
business.setDao(dao);
assertEquals(business.operate(), "test");
}
}
1
在工程中導入jmock-1.0.1.jar ,jmock-cglib-1.0.1.jar ,cglib-full-2.0.jar 三個jar包,然后在JUnit中執(zhí)行BusinessTest.java,會顯示綠棒,這樣,在沒有數(shù)據(jù)庫的情況下,單元測試成功。
使用JMock模擬類的條件:
1、要有無參數(shù)的構(gòu)造器;
2、構(gòu)造器是public;
這樣對于private的構(gòu)造器或單例模式的類應該是無法模擬了。這樣就要求我們養(yǎng)成針對接口編程的習慣,對接口用JMock進行模擬將不受這些限制。只需要將
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.cglib.Mock;
改為
import org.jmock.MockObjectTestCase;
import org.jmock.Mock;
即可。
對于Mock類,有很多API可供使用,比如:
isA(Class clz) 表示為某個類
isVoid() 將will()換成isVoid()表示無返回值
詳細API可以參考一下DOC,還會找到很多有用的東西
例如,有這樣兩個類,一個是Dao.java,用于數(shù)據(jù)庫訪問成操作的,一個是Business.java,需要調(diào)用Dao進行業(yè)務處理。Dao.java是已經(jīng)在有數(shù)據(jù)庫的環(huán)境測試通過的,現(xiàn)在需要測試Business.java。通常情況下,我們需要在測試環(huán)境配置好數(shù)據(jù)庫連接環(huán)境,并且需要準備數(shù)據(jù)后,才可以開始Business.java的測試,現(xiàn)在如果通過JMock就可以不配置數(shù)據(jù)庫環(huán)境,也可以完成測試。
//Dao.java
package com.raistlin.test.jmock
public class Dao
{
public Dao()
{
}
public List execute(String sql)
{
//數(shù)據(jù)庫操作...
}
}
//Business.java
package com.raistlin.test.jmock
public class Business
{
private Dao dao ;
public void setDao(Dao dao)
{
this.dao = dao;
}
public String operate()
{
List list = dao.execute("select * from tbl_test");
return (String) list.get(0);
}
}
//BusinessTest.java
package com.raistlin.test.jmock
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.cglib.Mock;
public class BusinessTest extends MockObjectTestCase
{
private Mock mockDao = null;
private Business business = null;
protected void setUp() throws Exception
{
super.setUp();
mockDao = new Mock(Dao.class);
business = new Business();
}
protected void tearDown() throws Exception
{
mockDao = null;
business = null;
super.tearDown();
}
public void testOperate()
{
ArrayList stubList = new ArrayList();
stubList.add("test\");
// 定義Mock劇本
mockDao.expects(once())// 期待次數(shù)
.method//Dao.java
package com.raistlin.test.jmock
public class Dao
{
public Dao()
{
}public List execute(String sql)
{
//數(shù)據(jù)庫操作...
}
}
//Business.java
package com.raistlin.test.jmock
public class Business
{
private Dao dao ;
public void setDao(Dao dao)
{
this.dao = dao;
}
public String operate()
{
List list = dao.execute("select * from tbl_test");
return (String) list.get(0);
}
}
//BusinessTest.java
package com.raistlin.test.jmock
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.cglib.Mock;
public class BusinessTest extends MockObjectTestCase
{
private Mock mockDao = null;
private Business business = null;
protected void setUp() throws Exception
{
super.setUp();
mockDao = new Mock(Dao.class);
business = new Business();
}
protected void tearDown() throws Exception
{
mockDao = null;
business = null;
super.tearDown();
}
public void testOperate()
{
ArrayList stubList = new ArrayList();
stubList.add("test");
// 定義Mock劇本
mockDao.expects(once())// 期待次數(shù)
.method("execute")// 調(diào)用方法
.with(eq("select * from tbl_test"))// 傳入?yún)?shù)等于
.will(this.returnValue(stubList));// 返回對象
Dao dao = (Dao) mockDao.proxy();
business.setDao(dao);
assertEquals(business.operate(), "test");
}
}
("execute")// 調(diào)用方法
.with(eq("select * from tbl_test"))// 傳入?yún)?shù)等于
.will(this.returnValue(stubList));// 返回對象
Dao dao = (Dao) mockDao.proxy();
business.setDao(dao);
assertEquals(business.operate(), "test");
}
}
1
在工程中導入jmock-1.0.1.jar ,jmock-cglib-1.0.1.jar ,cglib-full-2.0.jar 三個jar包,然后在JUnit中執(zhí)行BusinessTest.java,會顯示綠棒,這樣,在沒有數(shù)據(jù)庫的情況下,單元測試成功。
使用JMock模擬類的條件:
1、要有無參數(shù)的構(gòu)造器;
2、構(gòu)造器是public;
這樣對于private的構(gòu)造器或單例模式的類應該是無法模擬了。這樣就要求我們養(yǎng)成針對接口編程的習慣,對接口用JMock進行模擬將不受這些限制。只需要將
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.cglib.Mock;
改為
import org.jmock.MockObjectTestCase;
import org.jmock.Mock;
即可。
對于Mock類,有很多API可供使用,比如:
isA(Class clz) 表示為某個類
isVoid() 將will()換成isVoid()表示無返回值
詳細API可以參考一下DOC,還會找到很多有用的東西