[英]Mock Object and Interface
我是Mock Object單元測試的新手。 我使用EasyMock。 我試着理解這個例子:
import java.io.IOException;
public interface ExchangeRate {
double getRate(String inputCurrency, String outputCurrency) throws IOException;
}
import java.io.IOException;
public class Currency {
private String units;
private long amount;
private int cents;
public Currency(double amount, String code) {
this.units = code;
setAmount(amount);
}
private void setAmount(double amount) {
this.amount = new Double(amount).longValue();
this.cents = (int) ((amount * 100.0) % 100);
}
public Currency toEuros(ExchangeRate converter) {
if ("EUR".equals(units)) return this;
else {
double input = amount + cents/100.0;
double rate;
try {
rate = converter.getRate(units, "EUR");
double output = input * rate;
return new Currency(output, "EUR");
} catch (IOException ex) {
return null;
}
}
}
public boolean equals(Object o) {
if (o instanceof Currency) {
Currency other = (Currency) o;
return this.units.equals(other.units)
&& this.amount == other.amount
&& this.cents == other.cents;
}
return false;
}
public String toString() {
return amount + "." + Math.abs(cents) + " " + units;
}
}
import junit.framework.TestCase;
import org.easymock.EasyMock;
import java.io.IOException;
public class CurrencyTest extends TestCase {
public void testToEuros() throws IOException {
Currency testObject = new Currency(2.50, "USD");
Currency expected = new Currency(3.75, "EUR");
ExchangeRate mock = EasyMock.createMock(ExchangeRate.class);
EasyMock.expect(mock.getRate("USD", "EUR")).andReturn(1.5);
EasyMock.replay(mock);
Currency actual = testObject.toEuros(mock);
assertEquals(expected, actual);
}
}
所以,我想知道如何貨幣使用toEuros(..)
方法中的ExchangeRate。
rate = converter.getRate(units, "EUR");
未指定getRate(..)
方法的行為,因為ExchangeRate
是一個接口。
/********************************************************************************/
所以我嘗試做自己的例子。 以下是我的代碼:
/**
*Interface to access data
*/
public interface Dao {
public boolean getEntityById(int id) throws SQLException;
}
/**
*Business class do something in business layer
*/
public class Bussiness {
private Dao dao;
public Dao getDao() {
return dao;
}
public void setDao(Dao dao) {
this.dao = dao;
}
public boolean doSomeThing(int id) throws SQLException {
if(dao.getEntityById(id)) {
return true;
} else {
return false;
}
}
public static void main(String[] args) throws SQLException {
Bussiness b = new Bussiness();
b.doSomeThing(3);
}
}
package tunl;
import java.sql.SQLException;
import org.easymock.EasyMock;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
/**
* This is my unit Test
*/
@Test
public class MyUnitTest {
private Bussiness bussiness;
private Dao mock;
@BeforeTest
public void setUp() {
bussiness = new Bussiness();
mock = EasyMock.createMock(Dao.class);// interface not class
bussiness.setDao(mock);
}
public void testDoSomeThing() throws SQLException {
EasyMock.expect(mock.getEntityById(3)).andReturn(true);
EasyMock.replay(mock);
Assert.assertTrue(bussiness.doSomeThing(3));
}
}
所以,單位苔絲運行正常
但是當我想在Business Object中運行main方法時:
public static void main(String[] args) throws SQLException {
Bussiness b = new Bussiness();
b.doSomeThing(3);
}
我必須為Business添加構造函數。
public Bussiness() {
dao = new DaoImpl();
}
所以,我的商務艙是:
package tunl;
import java.sql.SQLException;
public class Bussiness {
private Dao dao;
public Bussiness() {
dao = new DaoImpl();
}
public Dao getDao() {
return dao;
}
public void setDao(Dao dao) {
this.dao = dao;
}
public boolean doSomeThing(int id) throws SQLException {
if(dao.getEntityById(id)) {
return true;
} else {
return false;
}
}
public static void main(String[] args) throws SQLException {
Bussiness b = new Bussiness();
b.doSomeThing(3);
}
}
我還要實現Dao接口:
package tunl;
import java.sql.SQLException;
public class DaoImpl implements Dao {
@Override
public boolean getEntityById(int id) throws SQLException {
if(id == 3) {
System.out.println("System input 3 ");
return true;
}
System.out.println("You have to input 3 ");
return false;
}
}
在設計中,您總是為將要測試的所有類創建接口(如DaoImpl)! 這是正確的嗎?
EasyMock基於界面創建模擬對象 。 模擬對象實現接口的所有方法以及您指定的那些方法(例如,使用expect
),它在調用時“重放”指定的行為。
創建模擬對象時,它處於錄制模式 。 這條線
EasyMock.expect(mock.getRate("USD", "EUR")).andReturn(1.5);
指定當使用給定參數調用mock.getRate
時,它將返回1.5。 然后通過調用將對象置於重放模式
EasyMock.replay(mock);
所有這些都在文檔中有更詳細的解釋。
更新:到您的評論 - Currency
在這里傳遞一個ExchangeRate
實例:
public Currency toEuros(ExchangeRate converter) { ... }
所有它關心的是它獲得一個實現該接口的對象,所以
rate = converter.getRate(units, "EUR");
可以叫。 然后,測試方法將其創建的模擬對象傳遞給貨幣對象:
Currency actual = testObject.toEuros(mock);
希望這可以幫助; 如果沒有,也許你可以閱讀一些關於OOP,接口和繼承的介紹性文本,以便更好地理解。
在你的答案中的代碼示例中, Dao
對象應該傳遞給Bussiness
而不是內部創建,因為后者有效地阻止了單元測試。
public static void main(String[] args) throws SQLException {
Bussiness b = new Bussiness();
b.setDao(new DaoImpl());
b.doSomeThing(3);
}
您還可以向Bussiness
添加參數化構造函數,以便在一步而不是兩步中進行初始化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.