JUnit4单元测试、JUnit4使用详解、assertThat用法

一.JUnit基本介绍

一、简介       

         JUnit是一个开放源码的、Java语言的单元测试框架,用于测试指望结果的断言(Assertion);由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework)。Junit测试是程序员测试,即所谓白盒测试,由于程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。多数Java的开发环境都已经集成了JUnit做为单元测试的工具,如Eclipse。程序员

        测试通常分为:单元测试、集成测试(主要看一块代码加进去后,系统会不会有问题)、验收测试和压力测试。单元测试的最基本的一个功能是能进行自动化测试。单元测试都是经过断言的方式来肯定结果是否正确,便是用Assert。编程

二、优势

        junit是在极限编程重构(refactor)中被极力推荐使用的工具,由于在实现自动单元测试的状况下能够大大的提升开发的效率。框架

        极限编程:要求在编写代码以前先写测试,这样能够强制你在写代码以前好好的思考代码(方法)的功能和逻辑,不然编写的代码很不稳定,那么你须要同时维护测试代码和实际代码,这个工做量就会大大增长。所以在极限编程中,基本过程是这样的:构思-> 编写测试代码-> 编写代码-> 测试,并且编写测试和编写代码都是增量式的,写一点测一点,在编写之后的代码中若是发现问题能够较快的追踪到问题的缘由,减少回归错误的纠错难度。less

        重构:其好处和极限编程中是相似的,由于重构也是要求改一点测一点,减小回归错误形成的时间消耗。maven

三、Junit3与Junit4

        在junit3中,若是某个类是测试类,必须将其继承类TestCase,若是某个方法是测试方法,必须让这个方法以testXX开头,若是但愿指定某个测试方法运行以前运行某个初始化方法,这个方法的名称必须是setUp,若是但愿在某个测试方法运行以后运行某个释放资源的方法,这个方法的名称必须是tearDown。
        在junit4中,一个POJO类就是一个测试类,测试方法经过@Test来标识,初始化方法经过@Before来标识,释放资源的方法经过@After来标识,可是为了让junit4的测试类在junit3中也可使用,习惯于把初始化方法命名为setUp,释放资源的方法命名为tearDown。Test中的测试方法通常以Test来开始。其中标识为Before注解的方法,每次运行测试类,都会执行标识为@After与@Before的方法。ide

 

二.JUnit单元测试

        因为JUnit4引用了不少Annotation注解之后,用JUnit进行单元测试比较方便,主要关键点在于:注解,断言的使用;函数

        如下为测试的示例:工具

待测试类单元测试

package com.test;

/**
 * 计算类
 * @author helen.
 * @Time 2016年5月13日
 * @Version 1.0
 */
public class Calculator {
	
	public int add(int a, int b) {  
		System.out.println("=======正在执行加法");
        return a + b;  
    }  
  
    public int minus(int a, int b) {  
    	System.out.println("=======正在执行减法");
        return a - b;  
    }  
  
    public int square(int n) {  
    	System.out.println("=======正在执行平方计算");
        return n * n;  
    }  
      
    //Bug : 死循环  
    public void squareRoot(int n) {  
    	System.out.println("=======正在执行死循环的方法");
        for(; ;)  
            ;  
    }  
      
    public int multiply(int a, int b) {  
    	System.out.println("=======正在执行乘法");
        return a * b;  
    }  
  
    public int divide(int a, int b) throws Exception { 
    	System.out.println("=======正在执行除法");
        if (0 == b) {  
            throw new Exception("除数不能为零");  
        }  
        return a / b;  
    }
    
}

单元测试类测试

package com.test;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import static org.hamcrest.Matchers.*;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;

/**
 * 计算类单元测试
 * @author helen.
 * @Time 2016年5月13日
 * @Version 1.0
 */
public class CalculatorTest {

	private Calculator cal = new Calculator();  
	  
	/**
	 * 注意
	 * 必须为静态方法static...由于方法将在类被装载的时候就被调用(那时候还没建立实例) 
	 * 
	 * @author helen, 2016年5月13日.
	 */
    @BeforeClass 
    public static void before()  
    {  
        System.out.println("global");  
    }  
  
    @AfterClass  
    public static void after() {  
        System.out.println("global destroy");  
    }  
  
    @Before  
    public void setUp() throws Exception {  
        System.out.println("one test begin");  
    }  
  
    @After  
    public void tearDown() throws Exception {  
        System.out.println("one test end");  
    }  
  
    @Test  
    @Ignore  
    public void testAdd() {  
        int result = cal.add(1, 2);  
        Assert.assertEquals(30, result);  
    }  
  
    @Test  
    public void testMinus() {  
        int result = cal.minus(5, 2);  
        Assert.assertThat(result, greaterThan(2));
    }

    @Test  
    public void testMultiply() {  
        int result = cal.multiply(4, 2);  
        Assert.assertEquals(8, result);  
    }  
  
    @Test(timeout = 1000) // 单位为毫秒  
    public void testSquareRoot() {  
        cal.squareRoot(4);  
    }  
  
    @Test(expected = Exception.class)  
    public void testDivide() throws Exception {  
        cal.divide(4, 0);  
    } 

}

    运行测试用:在Eclipse里Run As -> JUnit Test,运行测试类,Eclipse的JUnit的View显示以及控制台的输出以下截图: 

        能够看到,CalculatorTest类中总共有5个测试用例,ignore了一个,3个测试用例经过,testSquareRoot测试不经过(由于超时),因此整个的测试结果飘红了。

 

三.JUnit使用详解

一、注解说明

@Test:
代表该方法是一个测试方法
 
@BeforeClass 和 @AfterClass:
测试用例初始化时执行 @BeforeClass方法,当全部测试执行完毕以后,执行@AfterClass进行收尾工做。标注、@BeforeClass 和 @AfterClass的方法必须是static的,由于方法将在类被装载的时候就被调用,那时候还没建立测试对象实例。
 
@Before: 
使用了该元数据的方法在每一个测试方法执行以前都要执行一次。
@After: 
使用了该元数据的方法在每一个测试方法执行以后要执行一次。
 
@Test(expected=*.class) :
经过@Test元数据中的expected属性验证是否抛出指望的异常,expected属性的值是一个异常的类型,若是抛出了指望的异常,则测试经过,不然不经过。
 
@Test(timeout=xxx):
该元数据传入了一个时间(毫秒)给测试方法,若是测试方法在制定的时间以内没有运行完,则测试也失败。
 
@Ignore: 
该元数据标记的测试方法在测试中会被忽略。同时能够为该标签传递一个String的参数,来代表为何会忽略这个测试方法。好比:@lgnore("该方法尚未实现"),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。

 

二、经常使用断言

        在test方法内除了使用Assert的assertEquals()方法外,还能使用assertFalse()、assertTrue()、assertNull()、assertNotNull()、assertSame()、assertNotSame()等断言函数。并且若是使用的是Junit4,结合Hamcrest,使用
assertThat([value], [matcher statement])方法能够实现更灵活的断言判断(前提是引入hamcrest的jar包)。

        若是不须要用到assertThat,则只须要用Eclipse自带的junit4工具便可;若是须要用到assertThat,则最好不要Eclipse自带的工具,从新经过maven方式引入jar

<dependency>
		    <groupId>junit</groupId>
		    <artifactId>junit</artifactId>
		    <version>4.11</version>
		</dependency>				
		<dependency>
		    <groupId>org.hamcrest</groupId>
		    <artifactId>hamcrest-all</artifactId>
		    <version>1.3</version>
		</dependency>

 

四.assertThat用法(断言使用)

Hamcrest框架和assertThat:

1.JUnit4.4引入了Hamcrest框架,Hamcest提供了一套匹配符Matcher,这些匹配符更接近天然语言,可读性高,更加灵活;
2.使用全新的断言语法:assertThat,结合Hamcest提供的匹配符,只用这一个方法,就能够实现全部的测试;
3.assertThat语法以下:
     assertThat(T actual, Matcher<T> matcher);
     assertThat(String reason, T actual, Matcher<T> matcher);
     其中actual为须要测试的变量,matcher为使用Hamcrest的匹配符来表达变量actual指望值的声明;
4.注意事项:
     a.必须导入JUnit4.4以后的版本才能使用assertThat方法;
     b.不须要继承TestCase类,可是须要测试方法前必须加“@Test”。

 

经常使用:

// is匹配符代表若是前面待测的object等于后面给出的object,则测试经过 
assertThat( testedObj, is( object) ); 
 
// containsString匹配符代表若是测试的字符串包含指定的子字符串则测试经过
 assertThat( testedString, containsString( "developerWorks" ) );
 
// greaterThan匹配符代表若是所测试的数值testedNumber大于16.0则测试经过
 assertThat( testedNumber, greaterThan(16.0) ); 
 
// closeTo匹配符代表若是所测试的浮点型数testedDouble在20.0±0.5范围以内则测试经过 
assertThat( testedDouble, closeTo( 20.0, 0.5 ) );
 
//hasItem匹配符代表被测的迭代对象含有元素element项则测试经过assertThat(iterableObject, hasItem (element));

 

通常匹配符:

一、assertThat( testedNumber, allOf( greaterThan(8), lessThan(16) ) );
注释: allOf匹配符代表若是接下来的全部条件必须都成立测试才经过,至关于“与”(&&)
二、assertThat( testedNumber, anyOf( greaterThan(16), lessThan(8) ) );
注释:anyOf匹配符代表若是接下来的全部条件只要有一个成立则测试经过,至关于“或”(||)
三、assertThat( testedNumber, anything() );
注释:anything匹配符代表不管什么条件,永远为true
四、assertThat( testedString, is( "developerWorks" ) );
注释: is匹配符代表若是前面待测的object等于后面给出的object,则测试经过
五、assertThat( testedString, not( "developerWorks" ) );
注释:not匹配符和is匹配符正好相反,代表若是前面待测的object不等于后面给出的object,则测试经过

 

字符串相关匹配符

一、assertThat( testedString, containsString( "developerWorks" ) );
注释:containsString匹配符代表若是测试的字符串testedString包含子字符串"developerWorks"则测试经过
二、assertThat( testedString, endsWith( "developerWorks" ) ); 
注释:endsWith匹配符代表若是测试的字符串testedString以子字符串"developerWorks"结尾则测试经过
三、assertThat( testedString, startsWith( "developerWorks" ) ); 
注释:startsWith匹配符代表若是测试的字符串testedString以子字符串"developerWorks"开始则测试经过
四、assertThat( testedValue, equalTo( expectedValue ) ); 
注释: equalTo匹配符代表若是测试的testedValue等于expectedValue则测试经过,equalTo能够测试数值之间,字
符串之间和对象之间是否相等,至关于Object的equals方法
五、assertThat( testedString, equalToIgnoringCase( "developerWorks" ) ); 
注释:equalToIgnoringCase匹配符代表若是测试的字符串testedString在忽略大小写的状况下等于"developerWorks"则测试经过
六、assertThat( testedString, equalToIgnoringWhiteSpace( "developerWorks" ) );
注释:equalToIgnoringWhiteSpace匹配符代表若是测试的字符串testedString在忽略头尾的任意个空格的状况下等
于"developerWorks"则测试经过,注意:字符串中的空格不能被忽略

 

数值相关匹配符

一、assertThat( testedDouble, closeTo( 20.0, 0.5 ) );
注释:closeTo匹配符代表若是所测试的浮点型数testedDouble在20.0±0.5范围以内则测试经过
二、assertThat( testedNumber, greaterThan(16.0) );
注释:greaterThan匹配符代表若是所测试的数值testedNumber大于16.0则测试经过
三、assertThat( testedNumber, lessThan (16.0) );
注释:lessThan匹配符代表若是所测试的数值testedNumber小于16.0则测试经过
四、assertThat( testedNumber, greaterThanOrEqualTo (16.0) );
注释: greaterThanOrEqualTo匹配符代表若是所测试的数值testedNumber大于等于16.0则测试经过
五、assertThat( testedNumber, lessThanOrEqualTo (16.0) );
注释:lessThanOrEqualTo匹配符代表若是所测试的数值testedNumber小于等于16.0则测试经过

 

collection相关匹配符

一、assertThat( mapObject, hasEntry( "key", "value" ) ); 注释:hasEntry匹配符代表若是测试的Map对象mapObject含有一个键值为"key"对应元素值为"value"的Entry项则测试经过 二、assertThat( iterableObject, hasItem ( "element" ) ); 注释:hasItem匹配符代表若是测试的迭代对象iterableObject含有元素“element”项则测试经过 三、assertThat( mapObject, hasKey ( "key" ) ); 注释: hasKey匹配符代表若是测试的Map对象mapObject含有键值“key”则测试经过 四、assertThat( mapObject, hasValue ( "key" ) ); 注释:hasValue匹配符代表若是测试的Map对象mapObject含有元素值“value”则测试经过