1、java 单元测试篇:使用 clover 为 java 代码的 junit 测试做覆盖率分析本人最近在研究 java 单元测试技术,有点心得,这里分享给测试同行朋友!那么,今天我们研究的主题是使用 cenqua 公司的 clover 框架来分析 java 程序的单元测试覆盖率!关于 clover 的更多信息呢,请大家去 http:/ 去查询。我们这里,将会通过一个实例来演示如何使用 junit 和 clover 一起,来分析 java 代码的覆盖率。我们将会使用 ant 来编译一个 junit 单元测试实例项目,然后修改 build.xml 文件,加上 clover 的覆盖率分析任务 targ
2、et;而且我们还要通过三部分来学习 clover 超级无敌的地方:current 报告、历史报告以及高级特征!那么最开始呢,我们要做的就是从 http:/ 下载 clover 程序包clover.jar(它是 clover 的主要包) 、clover.license (clover 的试用 license,需要到官方网站下载一个月的试用注册文件,否则不能使用 clover!) 、velocity.jar(用来创建 html 报告的扩展包) ,将它们拷贝到 ant(ant 你已经安装好了,并且设置了 junit.jar 以及 ANT_HOME之类的初始化工作;我们这里不讲 ant 的基本使用,它
3、都流行这么多年了,这里假设你都懂啦!)的 lib 目录下,这样下来,我们在 ant 的 build.xml 文件里才可以使用 clover 任务!当然,现在很多朋友不喜欢配置一些环境变量,想把这些 jar 文件放在任意的地方,例如直接放在项目文件里,那么可以通过在 build.xml 文件里指定这些扩展包的位置也是可以的;如果在 build 文件里加入扩展包的路径,需要在 build 文件里这样写:1) 我们把下载来的 clover.jar 和 cenquatasks.jar 拷贝到你的项目目录的 lib 路径下2) 在 build.xml 下添加如下代码:之后你就可以在 ant 任务里构建
4、clover 的任务啦!其实最简单的办法呢,就是把clover.jar、clover.license、velocity.jar、cenquatasks.jar、junit.jar 这些包都拷贝到 ant 的 lib目录里,省得麻烦,不然将来你加入什么新功能,就会提示你找不到相应的包,你还得去网上搜,特不爽!我们的学习过程是:1) 先使用 junit 创建完 java 代码的测试代码,之后编译运行,完成 junit 对 java 代码的单元测试;2) 之后,我们在 ant 里构建测试任务,自动完成企业集的单元测试工作3) 然后,我们修改 build 文件,加入 clover 任务,来完整对单元测
5、试过程的覆盖率分析工作4) 之后开始重构代码,提高代码的单元测试覆盖率一、 构建 java 源代码与 junit 单元测试代码先在你的电脑里的某个比较顺眼的盘下建立一个目录,例如叫 sincky,这个就是我们的学习项目目录,再在 sincky 里创建一个 src 文件夹,用来放置所有的代码;之后在 src 里新建一个 java 类的源文件,名字叫做 IMoney.java,代码内容如下:public interface IMoney /* Adds a money to this money.*/public abstract IMoney add(IMoney m);/* Adds a si
6、mple Money to this money. This is a helper method for* implementing double dispatch*/public abstract IMoney addMoney(Money m);/* Adds a MoneyBag to this money. This is a helper method for* implementing double dispatch*/public abstract IMoney addMoneyBag(MoneyBag s);/* Tests whether this money is zer
7、o*/public abstract boolean isZero();/* Multiplies a money by the given factor.*/public abstract IMoney multiply(int factor);/* Negates this money.*/public abstract IMoney negate();/* Subtracts a money from this money.*/public abstract IMoney subtract(IMoney m);/* Append this to a MoneyBag m.*/public
8、 abstract void appendTo(MoneyBag m);这里我们定义一个 java 接口,表示了“金钱”这个神奇东西的一些美妙的抽象方法!早年有首迟志强的歌叫钞票:是谁制造的钞票,你在世上逞霸道,有人为你愁眉苦脸啊有人为你哈哈笑;姑娘为你走错了路,小伙子为你受改造!东奔又西跑,点头又哈腰,钞票!人人为你离不了钱哪!你这杀人不见血的刀形象无比,不扯了,跑题啦!I am back!之后我们实现这个接口,在 src 文件夹下定义一个叫做 Money.java 的类:public class Money implements IMoney private int fAmount;pri
9、vate String fCurrency;/* Constructs a money from the given amount and currency.*/public Money(int amount, String currency) fAmount= amount;fCurrency= currency;/* Adds a money to this money. Forwards the request to the addMoney helper.*/public IMoney add(IMoney m) return m.addMoney(this);public IMone
10、y addMoney(Money m) if (m.currency().equals(currency() )return new Money(amount()+m.amount(), currency();return MoneyBag.create(this, m);public IMoney addMoneyBag(MoneyBag s) return s.addMoney(this);public int amount() return fAmount;public String currency() return fCurrency;public boolean equals(Ob
11、ject anObject) if (isZero()if (anObject instanceof IMoney)return (IMoney)anObject).isZero();if (anObject instanceof Money) Money aMoney= (Money)anObject;return aMoney.currency().equals(currency()return false;public int hashCode() return fCurrency.hashCode()+fAmount;public boolean isZero() return amo
12、unt() = 0;public IMoney multiply(int factor) return new Money(amount()*factor, currency();public IMoney negate() return new Money(-amount(), currency();public IMoney subtract(IMoney m) return add(m.negate();public String toString() StringBuffer buffer = new StringBuffer();buffer.append(“+amount()+“
13、“+currency()+“);return buffer.toString();public /*this makes no sense*/ void appendTo(MoneyBag m) m.appendMoney(this);这个接口实现了 IMoney 接口的方法,具体语法就不讲了,很简单!之后,我们又用另一个类实现 IMoney 接口,为什么呢?你可以认为我贪心,但你不可以这么说,因为喜欢编程的人绝对不是为了贪婪代码!我们在 src 下建立另一个类 MoneyBag.java:import java.util.*;class MoneyBag implements IMoney
14、private Vector fMonies= new Vector(5);static IMoney create(IMoney m1, IMoney m2) MoneyBag result= new MoneyBag();m1.appendTo(result);m2.appendTo(result);return result.simplify();public IMoney add(IMoney m) return m.addMoneyBag(this);public IMoney addMoney(Money m) return MoneyBag.create(m, this);pub
15、lic IMoney addMoneyBag(MoneyBag s) return MoneyBag.create(s, this);void appendBag(MoneyBag aBag) for (Enumeration e= aBag.fMonies.elements(); e.hasMoreElements(); )appendMoney(Money)e.nextElement();void appendMoney(Money aMoney) if (aMoney.isZero() return;IMoney old= findMoney(aMoney.currency();if (
16、old = null) fMonies.addElement(aMoney);return;fMonies.removeElement(old);IMoney sum= old.add(aMoney);if (sum.isZero()return;fMonies.addElement(sum);public boolean equals(Object anObject) if (isZero()if (anObject instanceof IMoney)return (IMoney)anObject).isZero();if (anObject instanceof MoneyBag) Mo
17、neyBag aMoneyBag= (MoneyBag)anObject;if (aMoneyBag.fMonies.size() != fMonies.size()return false;for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) Money m= (Money) e.nextElement();if (!aMoneyBag.contains(m)return false;return true;return false;private Money findMoney(String currency) for
18、 (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) Money m= (Money) e.nextElement();if (m.currency().equals(currency)return m;return null;private boolean contains(Money m) Money found= findMoney(m.currency();if (found = null) return false;return found.amount() = m.amount();public int hashCo
19、de() int hash= 0;for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) Object m= e.nextElement();hash= m.hashCode();return hash;public boolean isZero() return fMonies.size() = 0;public IMoney multiply(int factor) MoneyBag result= new MoneyBag();if (factor != 0) for (Enumeration e= fMonies.e
20、lements(); e.hasMoreElements(); ) Money m= (Money) e.nextElement();result.appendMoney(Money)m.multiply(factor);return result;public IMoney negate() MoneyBag result= new MoneyBag();for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) Money m= (Money) e.nextElement();result.appendMoney(Money
21、)m.negate();return result;private IMoney simplify() if (fMonies.size() = 1)return (IMoney)fMonies.elements().nextElement();return this;public IMoney subtract(IMoney m) return add(m.negate();public String toString() StringBuffer buffer = new StringBuffer();buffer.append(“);for (Enumeration e= fMonies
22、.elements(); e.hasMoreElements(); )buffer.append(e.nextElement();buffer.append(“);return buffer.toString();public void appendTo(MoneyBag m) m.appendBag(this);之后,我们创建一个 junit 测试代码 MoneyTest.java,来测试 Money.java和 MoneyBag.java 类,这里我也把它放在 src 目录下;如果企业应用,你就要把目录分析的详细些,例如 src 子目录下放所有的 java 源代码,test 子目录下放所有
23、的 junit 测试代码:import junit.framework.*;public class MoneyTest extends TestCase private Money f12CHF;private Money f14CHF;private Money f7USD;private Money f21USD;private IMoney fMB1;private IMoney fMB2;public static void main(String args) junit.textui.TestRunner.run(MoneyTest.class);protected void se
24、tUp() f12CHF= new Money(12, “CHF“);f14CHF= new Money(14, “CHF“);f7USD= new Money( 7, “USD“);f21USD= new Money(21, “USD“);fMB1= MoneyBag.create(f12CHF, f7USD);fMB2= MoneyBag.create(f14CHF, f21USD);public void testBagMultiply() / 12 CHF7 USD *2 = 24 CHF14 USDIMoney expected= MoneyBag.create(new Money(
25、24, “CHF“), new Money(14, “USD“);assertEquals(expected, fMB1.multiply(2);assertEquals(fMB1, fMB1.multiply(1);assertTrue(fMB1.multiply(0).isZero();public void testBagNegate() / 12 CHF7 USD negate = -12 CHF-7 USDIMoney expected= MoneyBag.create(new Money(-12, “CHF“), new Money(-7, “USD“);assertEquals(
26、expected, fMB1.negate();public void testBagSimpleAdd() / 12 CHF7 USD + 14 CHF = 26 CHF7 USDIMoney expected= MoneyBag.create(new Money(26, “CHF“), new Money(7, “USD“);assertEquals(expected, fMB1.add(f14CHF);public void testBagSubtract() / 12 CHF7 USD - 14 CHF21 USD = -2 CHF-14 USDIMoney expected= Mon
27、eyBag.create(new Money(-2, “CHF“), new Money(-14, “USD“);assertEquals(expected, fMB1.subtract(fMB2);public void testBagSumAdd() / 12 CHF7 USD + 14 CHF21 USD = 26 CHF28 USDIMoney expected= MoneyBag.create(new Money(26, “CHF“), new Money(28, “USD“);assertEquals(expected, fMB1.add(fMB2);public void tes
28、tIsZero() assertTrue(fMB1.subtract(fMB1).isZero();assertTrue(MoneyBag.create(new Money (0, “CHF“), new Money (0, “USD“).isZero();public void testMixedSimpleAdd() / 12 CHF + 7 USD = 12 CHF7 USDIMoney expected= MoneyBag.create(f12CHF, f7USD);assertEquals(expected, f12CHF.add(f7USD);public void testBag
29、NotEquals() IMoney bag= MoneyBag.create(f12CHF, f7USD);assertFalse(bag.equals(new Money(12, “DEM“).add(f7USD);public void testMoneyBagEquals() assertTrue(!fMB1.equals(null);assertEquals(fMB1, fMB1);IMoney equal= MoneyBag.create(new Money(12, “CHF“), new Money(7, “USD“);assertTrue(fMB1.equals(equal);
30、assertTrue(!fMB1.equals(f12CHF);assertTrue(!f12CHF.equals(fMB1);assertTrue(!fMB1.equals(fMB2);public void testMoneyBagHash() IMoney equal= MoneyBag.create(new Money(12, “CHF“), new Money(7, “USD“);assertEquals(fMB1.hashCode(), equal.hashCode();public void testMoneyEquals() assertTrue(!f12CHF.equals(
31、null);Money equalMoney= new Money(12, “CHF“);assertEquals(f12CHF, f12CHF);assertEquals(f12CHF, equalMoney);assertEquals(f12CHF.hashCode(), equalMoney.hashCode();assertTrue(!f12CHF.equals(f14CHF);public void testMoneyHash() assertTrue(!f12CHF.equals(null);Money equal= new Money(12, “CHF“);assertEquals(f12CHF.hashCode(), equal.hashCode();public void testSimplify()