Struts測(cè)試之Mock Object測(cè)試
Struts測(cè)試之Mock Object測(cè)試
以下內(nèi)容引自
http://www.xgdown.com/article/239/47289_1.htm
使用Mock Object進(jìn)行測(cè)試,主要是用來(lái)模擬那些在應(yīng)用中不容易構(gòu)造(如HttpServletRequest必須在Servlet容器中才能構(gòu)造出來(lái))或者比較復(fù)雜的對(duì)象(如JDBC中的ResultSet對(duì)象)從而使測(cè)試順利進(jìn)行的工具。
JMock
簡(jiǎn)介
請(qǐng)?jiān)L問
http://www.jmock.org
。
準(zhǔn)備
1.???????
獲取
J2SDK
;
2.???????
獲取
JUnit V3.8.1
(從
http://www.junit.org
獲取開發(fā)包);
3.???????
獲取
JMock V1.0
(從
http://www.jmock.org
獲取
JMock
開發(fā)包)。
4.???????
為了開發(fā)方便,建議使用一個(gè)好
IDE
。以下例子中的代碼均是在
Eclipse V3.0
環(huán)境下進(jìn)行的調(diào)試。
以下是一個(gè)簡(jiǎn)單例子,代碼如下:
package test1;
import org.jmock.*;
import javax.servlet.http.*;
public class MockRequestTest extends MockObjectTestCase{
??? public void testMockRequest1(){
?????? //
構(gòu)造一個(gè)
Mock
對(duì)象
??????? Mock mock = new Mock(HttpServletRequest.class);
???????
??????? //
設(shè)置要執(zhí)行的操作,以下設(shè)置表示要調(diào)用一次
HttpServletRequest
對(duì)象的
??????? //getParameter
方法,傳遞的參數(shù)是
"name",
期望的返回是
"kongxx"
??????? mock.expects(once()).method("getParameter").with(eq("name")).will(returnValue("kongxx"));
???????
??????? //
根據(jù)
Mock
對(duì)象獲取一個(gè)
HttpServletRequest
對(duì)象
??????? HttpServletRequest request = (HttpServletRequest)mock.proxy();
???????
??????? //
斷言調(diào)用結(jié)果
??????? assertEquals("kongxx" ,request.getParameter("name"));???????
??? }
??? public void testMockRequest2(){
?????? //
構(gòu)造一個(gè)
Mock
對(duì)象
??????? Mock mock = new Mock(HttpServletRequest.class);
???????
??????? //
設(shè)置要執(zhí)行的操作,以下設(shè)置表示要調(diào)用一次
HttpServletRequest
對(duì)象的
??????? //getParameter
方法,傳遞的參數(shù)是
"name",
期望的返回是
"kongxx"
??????? mock.expects(once()).method("getParameter").with(eq("name")).will(returnValue("kongxx"));
???????
??????? //
根據(jù)
Mock
對(duì)象獲取一個(gè)
HttpServletRequest
對(duì)象
??????? HttpServletRequest request = (HttpServletRequest)mock.proxy();
???????
??????? //
調(diào)用
HttpServletRequest
對(duì)象的方法
??????? request.getParameter("name");???????
???????
??????? //
驗(yàn)證執(zhí)行結(jié)果
??????? mock.verify();
??? }
}
|
編譯并將其當(dāng)做一個(gè)
Test Case
運(yùn)行,會(huì)發(fā)現(xiàn)兩個(gè)測(cè)試方法均測(cè)試成功。
MyClass
需要測(cè)試的類,提供了兩個(gè)方法
getName
和
getPassword
,都使用
HttpServletRequest
作為輸入?yún)?shù)并返回從
HttpServletRequest
中取得的參數(shù),具體代碼如下:
package test2;
import javax.servlet.http.*;
public class MyClass {
??? public String getName(HttpServletRequest request) {
?????? return request.getParameter("name");
??? }
???
??? public String getPassword(HttpServletRequest request) {
?????? return request.getParameter("password");
??? }
} |
TestMyClass
測(cè)試類,其中構(gòu)造了一個(gè)假的
HttpServletRequest
對(duì)象,用來(lái)測(cè)試
MyClass
中的
getName
和
getPassword
方法,代碼如下:
package test2;
import org.jmock.*;
import javax.servlet.http.*;
public class TestMyClass extends MockObjectTestCase{
??? private MyClass myclass ;
??? private Mock mockRequest ;
??? private HttpServletRequest request ;
???
??? public void setUp() {??????
?????? myclass = new MyClass();
??????
?????? //
構(gòu)造一個(gè)
Mock
對(duì)象
?????? mockRequest = new Mock(HttpServletRequest.class);
??????
?????? //
根據(jù)
Mock
對(duì)象獲取一個(gè)
HttpServletRequest
對(duì)象
?????? request = (HttpServletRequest)mockRequest.proxy();
??? }
??? public void tearDown() {
?????? //TODO
??? }
??? public void testGetName(){
?????? //
設(shè)置要執(zhí)行的操作,以下設(shè)置表示要調(diào)用一次
HttpServletRequest
對(duì)象的
??????? //getParameter
方法,傳遞的參數(shù)是
"name",
期望的返回是
"kongxx"?????
?????? mockRequest.expects(atLeastOnce()).method("getParameter").with(eq("name")).will(returnValue("kongxx"));
??????
?????? assertNotNull(myclass.getName(request));
??????? assertEquals("kongxx" ,myclass.getName(request));??????
??? }
??? public void testGetPassword(){
?????? //
設(shè)置要執(zhí)行的操作,以下設(shè)置表示要調(diào)用一次
HttpServletRequest
對(duì)象的
??????? //getParameter
方法,傳遞的參數(shù)是
"password",
期望的返回是
"123456789" ?
???
??? mockRequest.expects(atLeastOnce()).method("getParameter").with(eq("password")).will(returnValue("123456789"));
??????
?????? assertNotNull(myclass.getPassword(request));
??????? assertEquals("123456789" ,myclass.getPassword(request));
??? }
} |
編譯并將其當(dāng)做一個(gè)
Test Case
運(yùn)行,會(huì)發(fā)現(xiàn)兩個(gè)測(cè)試方法均測(cè)試成功。
EasyMock
簡(jiǎn)介
請(qǐng)?jiān)L問
http://www.easymock.org
。
準(zhǔn)備
1.
???????
獲取
J2SDK
;
2.
???????
獲取
JUnit V3.8.1
(從
http://www.junit.org
獲取開發(fā)包);
3.
???????
獲取
EasyMock V1.1
(從
http://www.easymock.org
獲取
EasyMock
開發(fā)包)。
4.
???????
為了開發(fā)方便,建議使用一個(gè)好
IDE
。以下例子中的代碼均是在
Eclipse V3.0
環(huán)境下進(jìn)行的調(diào)試。
例子一
以下是一個(gè)簡(jiǎn)單例子,為了方便對(duì)比,這里重新實(shí)現(xiàn)了
JMock
例子一
,代碼如下:
package test1;
import org.easymock.*;
import junit.framework.*;
import javax.servlet.http.*;
public class MockRequestTest extends TestCase{
??? private MockControl control;
??? private HttpServletRequest mockRequest;
??? public void testMockRequest(){
?????? //
創(chuàng)建一個(gè)
Mock HttpServletRequest
的
MockControl
對(duì)象
?????? control = MockControl.createControl(HttpServletRequest.class);
??????
?????? //
獲取一個(gè)
Mock HttpServletRequest
對(duì)象
?????? mockRequest = (HttpServletRequest) control.getMock();
??????????
?????? //
設(shè)置期望調(diào)用的
Mock HttpServletRequest
對(duì)象的方法
?????? mockRequest.getParameter("name");
??????
?????? //
設(shè)置調(diào)用方法期望的返回值,并指定調(diào)用次數(shù)
?????? //
以下后兩個(gè)參數(shù)表示最少調(diào)用一次,最多調(diào)用一次
?????? control.setReturnValue("kongxx" ,1 ,1);??
??????
?????? //
設(shè)置
Mock HttpServletRequest
的狀態(tài),
?????? //
表示此
Mock HttpServletRequest
對(duì)象可以被使用
?????? control.replay();
??????
?????? //
使用斷言檢查調(diào)用
?????? assertEquals("kongxx",mockRequest.getParameter("name"));
??????
?????? //
驗(yàn)證期望的調(diào)用
?????? control.verify();
??? }
}
|
編譯并將其當(dāng)做一個(gè)
Test Case
運(yùn)行,會(huì)發(fā)現(xiàn)兩個(gè)測(cè)試方法均測(cè)試成功。
例子二
同例子一樣,對(duì)
JMock
例子二
重新實(shí)現(xiàn)產(chǎn)生了
EasyMock
的例子二。
需要測(cè)試的類代碼如下:
package test2;
import javax.servlet.http.*;
public class MyClass {
??? public String getName(HttpServletRequest request) {
?????? return request.getParameter("name");
??? }
???
??? public String getPassword(HttpServletRequest request) {
?????? return request.getParameter("password");
??? }
}
|
測(cè)試類代碼如下:
package test2;
import org.easymock.*;
import junit.framework.*;
import javax.servlet.http.*;
public class TestMyClass extends TestCase{
???
??? private MockControl control;
??? private HttpServletRequest mockRequest;
??? private MyClass myclass ;
???
??? public void setUp() {??????
?????? myclass = new MyClass();
??????
?????? //
創(chuàng)建一個(gè)
Mock HttpServletRequest
的
MockControl
對(duì)象
?????? control = MockControl.createControl(HttpServletRequest.class);
??????
?????? //
獲取一個(gè)
Mock HttpServletRequest
對(duì)象
?????? mockRequest = (HttpServletRequest) control.getMock();??????
??? }
??? public void tearDown() {
?????? //TODO
??? }
??? public void testGetName(){
?????? //
設(shè)置期望調(diào)用的
Mock HttpServletRequest
對(duì)象的方法
?????? mockRequest.getParameter("name");
??????
?????? //
設(shè)置調(diào)用方法期望的返回值,并指定調(diào)用次數(shù)
?????? //
以下后兩個(gè)參數(shù)表示最少調(diào)用一次,最多調(diào)用一次
?????? control.setReturnValue("kongxx" ,1 ,2);??
??????
?????? //
設(shè)置
Mock HttpServletRequest
的狀態(tài),
?????? //
表示此
Mock HttpServletRequest
對(duì)象可以被使用
?????? control.replay();
??????
?????? //
使用斷言檢查調(diào)用
?????? assertNotNull(myclass.getName(mockRequest));
?????? assertEquals("kongxx",myclass.getName(mockRequest));
??????
?????? //
驗(yàn)證期望的調(diào)用
?????? control.verify();???
??? }
??? public void testGetPassword(){
?????? //
設(shè)置期望調(diào)用的
Mock HttpServletRequest
對(duì)象的方法
?????? mockRequest.getParameter("password");
??????
?????? //
設(shè)置調(diào)用方法期望的返回值,并指定調(diào)用次數(shù)
?????? //
以下后兩個(gè)參數(shù)表示最少調(diào)用一次,最多調(diào)用一次
?????? control.setReturnValue("kongxx" ,1,2);
??????
?????? //
設(shè)置
Mock HttpServletRequest
的狀態(tài),
?????? //
表示此
Mock HttpServletRequest
對(duì)象可以被使用
?????? control.replay();
??????
?????? //
使用斷言檢查調(diào)用
?????? assertNotNull(myclass.getPassword(mockRequest));
?????? assertEquals("kongxx",myclass.getPassword(mockRequest));
??????
?????? //
驗(yàn)證期望的調(diào)用
?????? control.verify();??
??? }
}
|
編譯并將其當(dāng)做一個(gè)
Test Case
運(yùn)行,會(huì)發(fā)現(xiàn)兩個(gè)測(cè)試方法均測(cè)試成功。
獨(dú)立測(cè)試就是單獨(dú)測(cè)試一個(gè)類或方法里的代碼,而不測(cè)試?yán)锩嬲{(diào)用的其他類或方法的代碼。即假定調(diào)用的其他類或方法都正常執(zhí)行。
- 實(shí)際對(duì)象的行為還不確定。
- 實(shí)際的對(duì)象創(chuàng)建和初始化非常復(fù)雜。
- 實(shí)際對(duì)象中存在很難執(zhí)行到的行為(如網(wǎng)絡(luò)異常等)。
- 實(shí)際的對(duì)象運(yùn)行起來(lái)非常的慢。
- 實(shí)際對(duì)象是用戶界面程序。
- 實(shí)際對(duì)象還沒有編寫,只有接口等。
假定我們有對(duì)象A,它內(nèi)部頻繁調(diào)用了B中的方法。但是除了調(diào)用B的部分還存在自己的邏輯代碼。這時(shí),我們只想寫A的單體測(cè)試,而不想測(cè)試B(因?yàn)锽可能還沒編寫,只寫了實(shí)現(xiàn)的接口或者B運(yùn)行太慢了影響我們的測(cè)試效率)。這樣的話,我們就需要?jiǎng)?chuàng)建B的Mock對(duì)象。
換言之,我們現(xiàn)在不關(guān)心B,我們假定B的行為都能正常運(yùn)行。我們的目標(biāo)是假定B運(yùn)行正常的情況下,來(lái)對(duì)A進(jìn)行單體測(cè)試。
Mock對(duì)象就是我們先不用關(guān)心的對(duì)象,但是我們的關(guān)注對(duì)象對(duì)它有調(diào)用,所以我們給關(guān)注對(duì)象準(zhǔn)備個(gè)假貨讓它用。
?
posted on 2006-02-17 09:02 扭轉(zhuǎn)乾坤 閱讀(552) 評(píng)論(0) 編輯 收藏 所屬分類: Struts相關(guān)