天天看點

使用Cobertura統計JUnit測試覆寫率

完整版見https://jadyer.github.io/2013/07/09/junit-cobertura/

這是一個JavaProject,關于Cobertura的用法詳見代碼注釋

首先是應用代碼(即被測試的代碼)

package com.jadyer.service;

public class CalculatorService {
	public int add(int a, int b) {
		return a + b;
	}

	public int minus(int a, int b) {
		return a - b;
	}

	public int multiply(int a, int b) {
		return a * b;
	}

	public int divide(int a, int b) {
		if (0 == b) {
			throw new IllegalArgumentException("非法參數:除數不能為零..");
		}
		return a / b;
	}
}
           

下面是采用JUnit4.x編寫的測試代碼

package com.jadyer.service;

import org.junit.Assert;
import org.junit.Test;

/**
 * 使用Cobertura統計JUnit測試覆寫率
 * @see ----------------------------------------------------------------------------------------------------------
 * @see 生成測試覆寫率報告有三種方式(Maven--Ant--指令行)
 * @see Cobertura下載下傳位址為http://sourceforge.net/projects/cobertura/files/
 * @see Cobertura結合Maven使用起來是極為友善的,詳見http://blog.csdn.net/jadyer/article/details/7658734
 * @see Cobertura結合Ant生成報告也是非常友善的,詳見本文下方給出的build.xml
 * @see 最麻煩的就是用指令行(不推薦)
 * @see ----------------------------------------------------------------------------------------------------------
 * @see 通過指令行生成報告
 * @see 0)先交待下工程的目錄結構,src下存放應用代碼,test下存放測試代碼,bin下存放應用代碼和測試代碼的class檔案
 * @see 1)解壓cobertura-1.9.4.1-bin.zip到本地硬碟,并将D:\Develop\cobertura-1.9.4.1加入環境變量path
 * @see 2)将要測試的應用代碼、編譯之後的class檔案和所需jar拷到一個單獨的目錄中
 * @see   拷貝完畢後的目錄結構為D:\report\lib,D:\report\src,D:\report\bin(含所有的class檔案)
 * @see 3)在指令提示行中使用指令為要生成測試覆寫率報告的代碼生成一個ser檔案
 * @see   這一步主要的目的是為需要生成報告的class檔案加入Cobertura标記,用來告訴Cobertura哪些檔案需要生成測試覆寫率報告
 * @see   D:\report\bin>cobertura-instrument --destination instrumented com/jadyer/service
 * @see 4)基于ser檔案運作測試
 * @see   這一步主要的目的是跑一便JUnit測試,并将測試結果加入到第三步所标記的相對應的class檔案内,以便于下一步生成覆寫率報告
 * @see   D:\report\bin>java -cp ../lib/junit-4.10.jar;../lib/cobertura.jar;instrumented;.;-Dnet.source
 * @see   forge.cobertura.datafile=cobertura.ser org.junit.runner.JUnitCore com.jadyer.service.CalculatorServiceTest
 * @see 5)根據ser檔案生成測試覆寫率報告
 * @see   這一步主要的目的是生成報告,同時關聯第三步所标記的class檔案的源碼
 * @see   D:\report\bin>cobertura-report --format html --datafile cobertura.ser --destination reports ../src
 * @see 這裡面有兩點需要注意一下
 * @see 1)如果測試代碼的包名與應用代碼的包名相同(事實上這很正常),那麼通過以上5步所生成的報告中,會有一點無傷大雅的小問題
 * @see   那就是報告中即含有應用代碼的測試覆寫率報告(它會按照實際覆寫率顯示),也含有測試代碼的測試覆寫率報告(它會顯示100%)
 * @see   産生這一結果主要在于上面的第三步操作,由于包名相同故它會将測試代碼的class也納入報告标記的範圍内
 * @see   我曾試過為它加入--excludeClasses參數,發現竟沒有效果,可能我哪裡沒寫對,不深究了,反正以後也沒打算用指令行
 * @see   不過用本文提供的Ant腳本就不會出現這個問題了(Ant腳本中的<exclude name="/>是起作用的)
 * @see 2)若檔案編碼為UTF-8,則生成的報告中可能會亂碼,此時隻需為cobertura-report.bat增加-Dfile.encoding=UTF-8參數即可
 * @see   即為D:\Develop\cobertura-1.9.4.1\cobertura-report.bat檔案裡面的java指令加上此參數即可
 * @see ----------------------------------------------------------------------------------------------------------
 * @create Jul 6, 2013 6:18:16 PM
 * @author 玄玉<http://blog.csdn.net/jadyer>
 */
public class CalculatorServiceTest {
	@Test
	public void myAdd() {
		int result = new CalculatorService().add(1, 2);
		Assert.assertEquals(3, result);
	}

	@Test
	public void myMinus() {
		int result = new CalculatorService().minus(1, 2);
		Assert.assertEquals(-1, result);
	}

	@Test
	public void myMultiply() {
		int result = new CalculatorService().multiply(2, 3);
		Assert.assertEquals(6, result);
	}

	@Test
	public void myDivide() {
		int result = new CalculatorService().divide(6, 5);
		Assert.assertEquals(1, result);
	}
	
//	@Test(expected = IllegalArgumentException.class)
//	public void myDivideException() {
//		new CalculatorService().divide(6, 0);
//	}
}
           

下面附上我所使用的Ant腳本

<?xml version="1.0" encoding="UTF-8"?>
<project name="cobertura.junit.report" default="coverage" basedir=".">
	<!-- 這是一個JavaProject,目錄結構屬很典型的,即src下存放應用代碼,test下存放測試代碼,bin下存放應用代碼和測試代碼的class檔案 -->
	<property name="dir.lib" location="lib"/>
	<property name="dir.src" location="src"/>
	<property name="dir.test" location="test"/>
	<!-- 将生成測試覆寫率報告的有關檔案都統一放到report目錄下 -->
	<property name="dir.report" location="report"/>
	<!-- 将生成測試覆寫率報告時所生成的JUnit測試報告也統一放到report目錄下 -->
	<property name="dir.report.junit" location="report/junit"/>
	<!-- 将生成測試覆寫率報告所需的應用代碼和測試代碼的class也統一放到report目錄下 -->
	<property name="dir.report.class" location="report/class"/>
	<!-- 存放測試覆寫率報告結果的目錄,最後浏覽該目錄下的index.html就能看到報告了 -->
	<property name="dir.report.result" location="report/result"/>
	<!-- 用于存放生成測試覆寫率報告時所需的被Cobertura标記過的應用代碼class檔案的目錄 -->
	<property name="dir.report.instrument" location="report/instrument"/>
	
	<!-- 指明下面<javac/>時需用到的jar包,這裡最基本的需要用到下面6個jar -->
	<!-- junit-4.10.jar -->
	<!-- cobertura.jar    (取自下載下傳到的cobertura-1.9.4.1-bin.zip) -->
	<!-- asm-3.0          (取自下載下傳到的cobertura-1.9.4.1-bin.zip中的lib目錄) -->
	<!-- asm-tree-3.0     (取自下載下傳到的cobertura-1.9.4.1-bin.zip中的lib目錄) -->
	<!-- jakarta-oro-2.0.8(取自下載下傳到的cobertura-1.9.4.1-bin.zip中的lib目錄) -->
	<!-- log4j-1.2.9      (取自下載下傳到的cobertura-1.9.4.1-bin.zip中的lib目錄) -->
	<path id="app.classpath">
		<fileset dir="${dir.lib}">
			<include name="*.jar"/>
		</fileset>
	</path>
	
	<!-- 配置Cobatura ant擴充任務(其實這個tasks.properties是位于lib/cobertura.jar中的) -->
	<taskdef classpathref="app.classpath" target="_blank" rel="external nofollow"  resource="tasks.properties"/>
	
	<target name="init">
		<delete dir="${dir.report}"/>
		<mkdir dir="${dir.report.junit}"/>
		<mkdir dir="${dir.report.class}"/>
		<mkdir dir="${dir.report.instrument}"/>
	</target>
	
	<!-- 同時編譯應用代碼和測試代碼 -->
	<target name="compile" depends="init">
		<javac srcdir="${dir.src}:${dir.test}" destdir="${dir.report.class}" debug="true" encoding="UTF-8">
			<classpath refid="app.classpath"/>
		</javac>
	</target>
	
	<!-- 生成測試覆寫率報告(期間會進行JUnit測試) -->
	<target name="coverage" depends="compile">
		<cobertura-instrument todir="${dir.report.instrument}">
			<ignore regex="org.apache.log4j.*"/> 
			<!-- 指定需要生成代碼覆寫率報告的class -->
			<fileset dir="${dir.report.class}">
				<include name="**/**.class"/>
				<exclude name="**/*Test.class"/>
			</fileset>
		</cobertura-instrument>
		<!-- printsummary表示是否列印基本資訊,haltonfailure表示測試失敗是否中止,fork必須啟用,可設定為"on,true,yes"等-->
		<junit printsummary="on" haltοnerrοr="on" haltonfailure="on" fork="on">
			<!-- instrumented classes should be before the original (uninstrumented) classes -->
			<classpath location="${dir.report.instrument}"/>
			<classpath location="${dir.report.class}"/>
			<classpath refid="app.classpath"/>
			<!-- 同時運作多個測試用例,todir用來存放測試的輸出結果,如果不指定<formatter/>是不會輸出結果到todir中的 -->
			<formatter type="plain"/>
			<batchtest todir="${dir.report.junit}">
				<fileset dir="${dir.report.class}">
					<include name="**/*Test.class"/>
				</fileset>
			</batchtest>
		</junit>
		<!-- srcdir指定被測試的Java源碼目錄,destdir指定存放生成的報告的目錄(預設就會生成html格式的報告) -->
		<cobertura-report srcdir="${dir.src}" destdir="${dir.report.result}"/>
		<!-- 最後将ser檔案統一備份到報告目錄中(預設的會在build.xml的同一目錄下生成cobertura.ser) -->
		<move file="cobertura.ser" todir="${dir.report}"/>
	</target>
</project>
           

最後把項目的目錄結構和生成的測試覆寫率報告貼一下圖(共4張)

生成報告前的目錄結構如下

使用Cobertura統計JUnit測試覆寫率

生成報告後的目錄結構如下

使用Cobertura統計JUnit測試覆寫率

生成的測試覆寫率報告首頁截圖

使用Cobertura統計JUnit測試覆寫率

最後一張圖檔是檢視測試覆寫率詳情的截圖

使用Cobertura統計JUnit測試覆寫率