当测试一个方法,方法内需要用到一个对象,而这个对象的获取恰好又是不确定因素,可能他需要一段代码执行很长时间才能返回这个对象的值,也可能他目前不存在,将来会存在,比如定时任务一类,也可能它的获取非常的复杂,这个时候就需要考虑是不是先模拟出这个对象,然后按照正常的逻辑,将这个假的对象来测试这个方法是否正常按照逻辑走,这个对象的获取再单独用个测试用例来检查。Mock方法是单元测试中常见的一种技术,它的主要作用是模拟一些在应用中不容易构造或者比较复杂的对象,从而把测试与测试边界以外的对象隔离开。
EasyMock 是一套用于通过简单的方法对于给定的接口生成Mock对象的类库。它提供对接口的模拟,能够通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定的值或抛出指定异常。通过 EasyMock,我们可以方便的构造 Mock 对象从而使单元测试顺利进行。
官网:http://easymock.org/
不用手写 - 没有必要通过自己编写的模拟对象。
重构安全 - 重构接口方法的名称或重新排序的参数不会破坏测试代码在运行时创建。
返回值支持 - 支持返回值。
异常支持 - 支持例外/异常。
命令检查支持 - 支持检查命令方法调用。
注释支持 - 支持使用注解创建。
pom.xml配置:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.natongroupId>
<artifactId>MyTestartifactId>
<version>0.0.1-SNAPSHOTversion>
<properties>
<jdk.version>1.8jdk.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.easymockgroupId>
<artifactId>easymockartifactId>
<version>3.4version>
<scope>testscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.8.2version>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>${jdk.version}source>
<target>${jdk.version}target>
configuration>
plugin>
plugins>
build>
project>
Item.java文件:
public class Item {
private String name; //名字
private int quantity; //数目
public Item(String name, int quantity) {
super();
this.name = name;
this.quantity = quantity;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
Store.java文件
public class Store {
public double getPrice(String name) {
//可能是db獲取,也可能是其他方式
try {
Thread.sleep(3000000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 1;
}
}
ShoppingCar.java文件
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
public class ShoppingCar {
private String name;
private Store store = null;
private List- items = new ArrayList
- ();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List
- getItems()
{
return items;
}
public void setItems(List- items)
{
this.items = items;
}
public void addItem(Item item)
{
items.add(item);
}
public void setStore(Store store)
{
this.store=store;
}
public Store getStore()
{
return (this.store);
}
//計算 price
public Double calculateTotal() {
Double total = 0.0;
for (Item item : this.items) {
// 这里,依赖了一个额外的对象store,根据store.getPrice()方法求出某个商品的单价,
//但这里模拟的是现在根本不知道这个store 是如何实现的,有可能是第三方的,什么时候能够拿到值也不确定,也就是说不确定因素很多。
total+= (store.getPrice(item.getName()) * item.getQuantity());
}
DecimalFormat decim = new DecimalFormat("0.00");
Double price = Double.parseDouble(decim.format(total));
return price;
}
}
这里我们主要测试calculateTotal()这个方法,测试用例如下:
import static org.junit.Assert.assertEquals;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class ShoppingCarTest {
public ShoppingCar cart = null; //要测试的内容
public Store storeMock = null; //要模拟的对象
@Before
public void initialize() {
System.out.println("----@Before------");
cart = new ShoppingCar();
storeMock = EasyMock.createMock(Store.class);
cart.setStore(storeMock);
}
@Test
public void testShoppingCart() {
EasyMock.expect(storeMock.getPrice("Notebook")).andReturn(5.99);
EasyMock.expect(storeMock.getPrice("Kindle")).andReturn(499.99);
//开始使用mock
EasyMock.replay(storeMock);
//产品 价格 数目
Item item1 = new Item("Notebook", 5);
Item item2 = new Item("Kindle",1);
//放入购物车
cart.addItem(item1);
cart.addItem(item2);
//计算总额
double total = cart.calculateTotal();
System.out.println("总额: $"+total);
//进行判断
assertEquals("Result",529.94, total,0);
}
@Test
public void testShoppingCartWrongResult() {
EasyMock.expect(storeMock.getPrice("Notebook")).andReturn(5.99);
EasyMock.expect(storeMock.getPrice("Kindle")).andReturn(499.99);
//开始使用mock
EasyMock.replay(storeMock);
//产品 价格 数目
Item item1 = new Item("Notebook", 5);
Item item2 = new Item("Kindle",1);
//放入购物车
cart.addItem(item1);
cart.addItem(item2);
//计算总额
double total = cart.calculateTotal();
System.out.println("总额: $"+total);
//进行判断
assertEquals("Result",515.96, total,0);
}
@Test
public void testShoppingCartCauseError() {
EasyMock.expect(storeMock.getPrice("Notebook")).andThrow(new RuntimeException("异常发生了"));
EasyMock.expect(storeMock.getPrice("Kindle")).andReturn(499.99);
//开始使用mock
EasyMock.replay(storeMock);
//产品 价格 数目
Item item1 = new Item("Notebook", 5);
Item item2 = new Item("Kindle",1);
//放入购物车
cart.addItem(item1);
cart.addItem(item2);
//计算总额
double total = cart.calculateTotal();
System.out.println("总额: $"+total);
//进行判断
assertEquals("Result",525.96, total,0);
}
@After
public void cleanup(){
System.out.println("----@After------");
cart=null;
storeMock=null;
}
}
上面就是简单的一个easyMock使用过程。EasyMock还有一些高级用法,参考文章 http://www.yiibai.com/easymock/easymock_junit_integration.html