EasyMock總覽
下面,我將講述如何使用JUnit和EasyMock框架來進行單元測試。
在現實情況下,我們通常是在一些類裏使用另外的一些類。在進行真正的測試之前,你可能需要做很多的工作,比喻說安置大量的環境代碼,啓動一種大型的、複雜的系統,可能是數據庫、功過劉或者是某一種類型的IDE環境,你的預設環境代碼需要是系統進入某種特定的狀態,以便按照測試所需要的方法進行響應。但是這種工作不大可能很快就能完成。
爲了對一部分類進行單元測試,你需要建立和控制另外一些類。最好的辦法就是爲需要測試的類創建一個模擬對象。你可以自己手工的編寫類,也可以使用EasyMock來產生這些對象。
模擬對象提供了一種經過證明是成功的解決方案。當我們很難或不可能爲某種難以處理的資源創建需要的狀態或者存取某種資源受限時,你就可以使用模擬對象。
模擬對象取代真實對象的位置,用於測試一些與真實對象進行交互或依賴於真實對象的功能。模擬對象背後的基本思想就是創建輕量級的、可控制的對象來代替爲了編寫測試爲需要使用的對象。模擬對象還能夠讓你指定和測試你的代碼與模擬對象本身之間的交互。
說的再直白一點,一個模擬對象就是一個簡單的接口或者是類,在裏面你可以定義一個特定的方法調用之後的簡單的輸出。
所需jar包
EasyMock的使用,需要兩個jar包,Junit和EasyMock的jar包,
你可以自己從官網上分別下載它們,也可以從下面的地址下載:
Junit4.11:http://download.csdn.net/detail/zyh5540/5860807
EasyMock3.2:http://download.csdn.net/detail/zyh5540/5860785
其中使用Junit時可能提示缺少hamcrest的jar包,這時你需要導入該jar包,同時你可以去Junit的官網下載hamcrest的jar包,此時需要主義Junit和harmcrest之間的版本號對應關係,這個也可以從官網上查得到。如果是從我上邊提供的鏈接下載的,不需要單獨在下載了。
示例
package easymock.income;
/**
* Position類表示職位信息,總共有三類:老闆,程序猿,管理員
*/
public enum Position {
BOSS,PROGRAMMER,MANAGER
}
package easymock.income.method;
import easymock.income.Position;
/**
* 定義的計算工資的接口
* 並有一個抽象方法:計算工資
*/
public interface ICalMethod {
public abstract double cal(Position position);
}
package easymock.income;
import easymock.income.Position;
import easymock.income.exception.CalMethodException;
import easymock.income.exception.PositionException;
import easymock.income.method.ICalMethod;
/**
* 收入(工資)計算的實現類,該類根據計算方法和職員的職位
* 計算該職員的工資
*/
public class IncomeCaculator {
private ICalMethod method;
private Position position;
public void setMethod(ICalMethod method) {
this.method = method;
}
public void setPosition(Position position) {
this.position = position;
}
public double cal() {
//計算的方法類爲空,拋計算方法空異常
if(null == method){
throw new CalMethodException("cal method is null");
}
//當職位爲空時,拋職位爲空異常
if(null == position) {
throw new PositionException("position is null");
}
//返回該職員的工資
return method.cal(position);
}
}
package easymock.income;
import easymock.income.exception.CalMethodException;
import easymock.income.exception.PositionException;
import easymock.income.method.ICalMethod;
/**
* 收入(工資)計算的實現類,該類根據計算方法和職員的職位
* 計算該職員的工資
*/
public class IncomeCaculator {
private ICalMethod method;
private Position position;
public void setMethod(ICalMethod method) {
this.method = method;
}
public void setPosition(Position position) {
this.position = position;
}
public double cal() {
//計算的方法類爲空,拋計算方法空異常
if(null == method){
throw new CalMethodException("cal method is null");
}
//當職位爲空時,拋職位爲空異常
if(null == position) {
throw new PositionException("position is null");
}
//返回該職員的工資
return method.cal(position);
}
}
以下是方法爲空的異常類和職位爲空的異常類:
package easymock.income.exception;
public class CalMethodException extends RuntimeException {
private static final long serialVersionUID = 1L;
public CalMethodException(String message) {
super(message);
}
}
package easymock.income.exception;
public class PositionException extends RuntimeException {
private static final long serialVersionUID = 1L;
public PositionException(String message) {
super(message);
}
}
package easymock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import easymock.income.IncomeCaculator;
import easymock.income.Position;
import easymock.income.exception.CalMethodException;
import easymock.income.exception.PositionException;
import easymock.income.method.ICalMethod;
/**
* EasyMock的使用步驟:
* 使用 EasyMock 生成 Mock 對象
* 設定 Mock 對象的預期行爲和輸出;
* 將 Mock 對象切換到 Replay 狀態;
* 調用 Mock對象方法進行單元測試; 對 Mock 對象的行爲進行驗證。
*
*/
public class EasyMockTest {
private ICalMethod calMethod;
private IncomeCaculator caculator;
@Before
public void setUpBeforeClass() throws Exception {
//第一步:生成Mock對象
calMethod = EasyMock.createMock(ICalMethod.class);
caculator = new IncomeCaculator();
}
@Test
public void testCacl1() {
/**
* 設定 Mock 對象的預期行爲和輸出
*/
//計算方法的參數是Position.BOSS,
//andReturn(),期望calMethod方法返回的是7000.0
//times(),該方法執行次數爲兩次
EasyMock.expect(calMethod.cal(Position.BOSS)).andReturn(7000.0)
.times(2);
//默認執行次數爲一次
EasyMock.expect(calMethod.cal(Position.PROGRAMMER)).andReturn(5000.0);
//將 Mock 對象切換到 Replay 狀態
EasyMock.replay(calMethod);
/**
* 調用 Mock 對象方法進行單元測試
* 代碼的參數設置及返回結果應參考上面預期行爲的設定
* 方法的執行順序應和上面的一致
*/
caculator.setMethod(calMethod);
try {
caculator.cal();
fail("exception is not occur");
} catch (PositionException e) {
System.out.println("position exception");
}
caculator.setPosition(Position.BOSS);
//判斷結果是否和預期的一樣
//第一次預期的執行
//這裏應該讓caculator.cal()方法執行兩次,這個次數和上面設定的次數一致
assertEquals(caculator.cal(), 7000.0, 0);
assertEquals(caculator.cal(), 7000.0, 0);
//第二次預期的執行
caculator.setPosition(Position.PROGRAMMER);
assertEquals(5000.0, caculator.cal(), 0);
caculator.setPosition(Position.MANAGER);
//對 Mock對象的行爲進行驗證,驗證是否兩次預期都已執行
EasyMock.verify(calMethod);
}
//測試能否拋出計算方法爲空的異常
@Test(expected = CalMethodException.class)
public void testNoCalc() {
caculator.setPosition(Position.MANAGER);
caculator.cal();
}
@Test(expected = PositionException.class)
public void testNoPosition() {
EasyMock.expect(calMethod.cal(Position.BOSS)).andReturn(7000.0);
EasyMock.replay(calMethod);
caculator.setMethod(calMethod);
caculator.cal();
}
@Test(expected = PositionException.class)
public void testCalc2() {
//andThrow(),預期拋出一個異常
EasyMock.expect(calMethod.cal(Position.MANAGER))
.andThrow(new PositionException("Don't know this guy"))
.times(1);
EasyMock.replay(calMethod);
caculator.setPosition(Position.MANAGER);
caculator.setMethod(calMethod);
caculator.cal();
}
}