说到代码覆盖率,你肯定会想到Jacoco, 其实JMockit相比Jacoco,做代码覆盖率,一样很强大。如果你关心代码的路径覆盖率,JMockit有,而Jacoco没有! 

   
  那我们该如何配置JMockit做覆盖率呢?很简单,只需要在pom.xml给surefire(即mvn test背后的maven插件)配置一些参数即可。

    在pom.xml中<project><build><plugins>节点给插件surefire增加一些参数即可。

<plugin>
       <artifactId>maven-surefire-plugin</artifactId>
	<version>2.20</version>
	<configuration>
	<disableXmlReport>true</disableXmlReport>
	<argLine>-Dcoverage-metrics=all</argLine>
	</configuration>
</plugin>


  执行mvn test后呢?去哪里看覆盖率呢?  target/coverage-report目录下,用浏览器找开index.html,就可以看了。


    JMockit给我们提供的行覆盖率,路径覆盖率,数据覆盖率。
    行覆盖率是从代码行的维度进行统计,哪些行被测试到了,本文不做详细介绍了。
    数据覆盖率是指一个类的哪些非静态属性被修改过了,这个不常用,指导意义也不大。本文也不做详细介绍了。
    本文重点介绍一下,JMockit的路径覆盖率和Jacoco的分支覆盖率,这2个是非常容易混淆的概念。

    咱们先拿几个简单的类来做测试,并分别看其JMockit的路径覆盖率结果,Jacoco的分支覆盖率结果。

   比如要测试这个简单的类,

//打招呼的接口
public interface ISayHello {
	// 性别:男
	int MALE = 0;
	// 性别:女
	int FEMALE = 1;

	/**
	 * 打招呼
	 * 
	 * @param who    向谁说
	 * @param gender 对方的性别
	 * @return 返回打招呼的内容
	 */
	String sayHello(String who, int gender);

	/**
	 * 向多个人打招呼
	 * 
	 * @param who    向谁说
	 * @param gender 对方的性别
	 * @return 返回向多个人打招呼的内容
	 */
	List<String> sayHello(String[] who, int[] gender);

}



public class SayHello implements ISayHello {
	@Override
	public String sayHello(String who, int gender) {
		// 性别校验
		if (gender != FEMALE) {
			if (gender != MALE) {
				throw new IllegalArgumentException("illegal gender");
			}
		}
		// 根据不同性别,返回不同打招呼的内容
		switch (gender) {
		case FEMALE:
			return "hello Mrs " + who; 
		case MALE:
			return "hello Mr " + who;
		default:
			return "hello  " + who;
		}
	}

	@Override
	public List<String> sayHello(String[] who, int[] gender) {
		// 参数校验
		if (who == null || gender == null) {
			return null;
		}
		if (who.length != gender.length) {
			throw new IllegalArgumentException();
		}
		//把向每个人打招呼的内容,保存到result中。
		List<String> result = new ArrayList<String>();
		for (int i = 0; i < gender.length; i++) {
			result.add(this.sayHello(who[i], gender[i]));
		}
		return result;
	}

}



  上面2个类,一个是接口,另一个是实现该接口的类。 类的功能十分简单,就是向别人打招呼。  假设现在我们要测试SayHello这个类。

测试代码如下:

//代码覆盖率测试,观察覆盖率的计算方式,去target/coverage-report目录下,查看SayHello这个类的覆盖率
public class CodeCoverageTest {
	ISayHello sayHello = new SayHello();

	@Rule
	public ExpectedException thrown = ExpectedException.none();

	//测试 sayHello(String who, int gender);
	@Test
	public void testSayHello1() {
		Assert.isTrue(sayHello.sayHello("david", ISayHello.MALE).equals("hello Mr david"));
		Assert.isTrue(sayHello.sayHello("lucy", ISayHello.FEMALE).equals("hello Mrs lucy"));
		thrown.expect(IllegalArgumentException.class);
		sayHello.sayHello("david", 3);
	}
	//测试 sayHello(String[] who, int[] gender)
	@Test
	public void testSayHello2() {
		String[] who = new String[] { "david", "lucy" };
		int[] gender = new int[] { ISayHello.MALE, ISayHello.FEMALE };
		List<String> result = sayHello.sayHello(who, gender);
		Assert.isTrue(result.get(0).equals("hello Mr david"));
		Assert.isTrue(result.get(1).equals("hello Mrs lucy"));
	}

}


  测试代码功能也十分简单,用几种常用的入参做了测试。 测试运行后(mvn test或idea/eclipse运行测试),就在target/coverage-report目录下,生成了覆盖的结果,从结果中,我们可以打开SayHello类的覆盖率结果。


 


    接下来,我们再用Jacoco来做覆盖率的统计(Jacoco的使用方法,本文这里不就介绍了), 其分支覆盖率测试结果如下:




      上图中,已经描述了JMockit路径覆盖率与Jacoco分支覆盖率的区别。
    你更喜欢哪一个呢?反正我比较喜欢JMockit路径覆盖率,因为JMockit的路径覆盖率报告中,清晰了标注了类的方法有哪些执行路径,每一个执行路径不正是我们单元测试的测试目标么?