Junit4 实践参考

来源:互联网 发布:西成高铁 知乎 编辑:程序博客网 时间:2024/06/05 02:51

大纲:

(一)确定测试用例类的运行Runner

1)@RunWith(BlockJUnit4ClassRunner.class)

BlockJUnit4ClassRunner则是Juint4默认的运行器,叫成Block是因为他是按 
顺序一个一个执行测试用例的,Junit4中没有提供实现多线程执行的运行器。

2)@RunWith(Parameterized.class)

测试方法内容相同,仅仅只是测试数据有差异而已的测试类

3)@RunWith(Suite.class)

一般在一个项目中,只写一个测试类是不可能的,我们会写出很多很多个测试类。如何这些测试类必须一个一个的执行,也是非常麻烦的事情。鉴于此,JUnit为我们提供了打包测试的功能,将所有需要运行的测试类集中起来,一次性的运行完毕,这大大的方便了我们的测试工作。

参考:Junit4 Runner特性分析http://www.mysjtu.com/page/M0/S541/541699.html


(二)测试对象的创建,以及资源设置与释放

1)测试对象创建

如果测试对象构建比较简单,那么测试对象一般可以定义成为测试类的静态数据成员

如果测试对象创建比较麻烦,则定义成为普通数据成员,再@Before,After或者@BeforeClass,@AfterClass中创建

2)@Before,@After

每一个测试方法都是独立的,相互之间没有任何耦合度。 因此,我们就很有必要在执行每一个测试之前,需要对被测对象做"复原操作"以消除其他测试造成的影响。 因此,"在任何一个测试执行之前和之后必须执行的代码"就是Fixture 我们用@Before,@After标注

3)@BeforeClass,@AfterClass

@Before和@After是每个测试方法执行前后均需要执行, 因此不适合累中耗资源,或者耗时过大的操作。

@BeforeClass 和 @AfterClass两个Fixture来帮规避此问题。
从名字上就可以看出,用这两个Fixture标注的函数,只在测试用例 初始化时执行 @BeforeClass方法,当所有测试执行完毕之后,执行
@AfterClass进行收尾工作。在这里要注意一下,每个测试类只能有 一个方法被标注为 @BeforeClass 或 @AfterClass, 并且该方法必须是Public和Static的

参考:http://blog.csdn.net/xuxuxiaojie/article/details/5628671


(三)测试方法定义

1)忽略没有完成的测试方法 @Ignore

测试函数的前面加上@Ignore标注,这个标注的含义就是"某些方法尚未完成,暂不参与此次测试"。这样的话测试结果就会提示你有几个测试被忽略,而不是失败。 一旦你完成了相应函数,只需要把@Ignore标注删去,就可以进行正常的测试。

@Ignore
@Test
public void testUsingIgnore() {
}

2)测试超时运行的测试方法@Test(timeout= ms)

对于那些逻辑很复杂,循环嵌套比较深的程序, 很有可能出现死循环,因此一定要采取一些预防措 施。
限时测试是一个很好的解决方案。我们给这些测试函数设定 一个执行时间,超过了这个时间,他们就会被系统强行终止, 并且系统还会向你汇报该函数结束的原因是因为超时,这样你就可以发现这些Bug了

@Test(timeout = 1000)// 单位为毫秒
public void testUsingTimeout() {
}

3)测试方法测试异常@Test(expected=)

测试 使用@Test标注的expected属性,将我们要检验的异常传递给他,这样JUnit框架就能自动帮我们检测是否抛出了我们指定的异常

@Test(expected = Exception.class)
public void testExceptionThrowing() {
}

参考:http://blog.csdn.net/xuxuxiaojie/article/details/5628671


(四)具体介绍@RunWith(Parameterized.class)

@RunWith(Parameterized.class)
public class SquareTest {
    private static Calculator calculator = new Calculator();
    private int param1;

    private int param2;

.....................
    private int result;

@Parameters
    public static Collection date(){
        return Arrays.asList(new Object[][]{
            {2,2, 4},
            {0, 0,0},
            {-3,3,9},
      });
    }

    public SquareTest(int param1,int param2, int result) {
           this.param1 = param1;

   this.param2 = param2;
           this.result = result;
    }
    @Test
    public void add() {
        calculator.add(param1,param2);
        assertEquals(result, calculator.getResult());
    }
    
}

(五)具体介绍@RunWith(Suite.class)

向@RunWith标注传递一个参数Suite.class。
同时,我们还需要另外一个标注@Suite.SuiteClasses,来表明这个类是一个打包测试类。我们把需要打包的类作为参数传递给该标注就可以了。
有了这两个标注之后,就已经完整的表达了所有的含义,因此下面的类已经无关紧要,随便起一个类名,内容全部为空既可

@RunWith(Suite.class)
@Suite.SuiteClasses({
        CalculatorTest.class,
        SquareTest.class
        })
public class AllCalculatorTests {
}


(六) import static

 import static,这是一个静态包含(static),是JDK5中新增添的一个功能。也就是说,assertEquals是Assert类中的一系列的静态方法,
  一般的使用方式是Assert. assertEquals(),但是使用了静态包含后,前面的类名就可以省略了,使用起来更加的方便


(七)TODO

..................


---------------------------------------------------------------------------------------------------------------------------------------------------------------------

转载引用:

第一步:eclipse中新建一个项目,java build path中导入junit jar包(本文例子junit-4.9b1.jar)

第二步:新建一个package,导入如下四个文件

第三步:右键AllCalculatorTests(或者CalculatorTest、SquareTest),run as junit test,查看执行结果。

代码中的注释能够帮你理解Junit4。

 

=================================================================

package andycpp;

public class Calculator {
    private static int result; // 静态变量,用于存储运行结果
    public void add(int n) {
        result = result + n;
    }
    public void substract(int n) {
        result = result - 1;  //Bug: 正确的应该是 result =result-n
    }
    public void multiply(int n){
    }         // 此方法尚未写好
    public void divide(int n) {
        result = result / n;
    }
    public void square(int n) {
        result = n * n;
    }
    public void squareRoot(int n) {
        for (; ;) ;            //Bug : 死循环
    }
    public void clear() {     // 将结果清零
        result = 0;
    }
    public int getResult() {
        return result;
    }
}
===============================================================

package andycpp;
/*
 * import static,这是一个静态包含(static),是JDK5中新增添的一个功能。也就是说,assertEquals是Assert类中的一系列的静态方法,
 * 一般的使用方式是Assert. assertEquals(),但是使用了静态包含后,前面的类名就可以省略了,使用起来更加的方便
 * */
import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
//测试类名称任意

public class CalculatorTest {
    //你要测试哪个类,那么你首先就要创建一个该类的对象
    private static Calculator calculator = new Calculator();
    /*
     * @Before和@After是每个测试方法执行前后均需要执行,
     * 因此不适合累中耗资源,或者耗时过大的操作。
     * @BeforeClass 和 @AfterClass两个Fixture来帮规避此问题。
     * 从名字上就可以看出,用这两个Fixture标注的函数,只在测试用例
     * 初始化时执行 @BeforeClass方法,当所有测试执行完毕之后,执行
     * @AfterClass进行收尾工作。在这里要注意一下,每个测试类只能有
     * 一个方法被标注为 @BeforeClass 或 @AfterClass,
     * 并且该方法必须是Public和Static的
     * */
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }
    /*
     * 我们非常希望每一个测试都是独立的,相互之间没有任何耦合度。
     * 因此,我们就很有必要在执行每一个测试之前,对Calculator对象进行一个“复原”操作,
     * 以消除其他测试造成的影响。因此,“在任何一个测试执行之前必须执行的代码”就是一个Fixture,
     * 我们用@Before来标注它     这里不在需要@Test标注* 
     * */
    @Before
    public void setUp() throws Exception {
        calculator.clear();
    }

    @After
    public void tearDown() throws Exception {
    }
   //@Test 标准的方法,返回值必须是void,而且无参数
    @Test
    public void testAdd() {
        calculator.add(2);
        calculator.add(3);
        assertEquals(5,calculator.getResult());//第一个参数填写期待结果,第二个参数填写实际结果
        
    }

    @Test
    public void testSubstract() {
        calculator.add(10);
        calculator.substract(2);
        assertEquals(8,calculator.getResult());
    }
    /*
     * 如果你已经把该方法的测试用例写完,但该方法尚未完成,那么测试的时候一定是“失败”。
     * 这种失败和真正的失败是有区别的,因此JUnit提供了一种方法来区别他们,那就是在这种
     * 测试函数的前面加上@Ignore标注,这个标注的含义就是“某些方法尚未完成,暂不参与此次测试”。
     * 这样的话测试结果就会提示你有几个测试被忽略,而不是失败。一旦你完成了相应函数,只需要把@Ignore标注删去,
     * 就可以进行正常的测试。
     * */
    @Ignore
    @Test
    public void testMultiply() {
        calculator.add(2);
        calculator.multiply(3);
        assertEquals(6,calculator.getResult());
    }

    @Test
    public void testDivide() {
         calculator.add(8);
         calculator.divide(2);
         assertEquals(4, calculator.getResult());
    }
    /*
     * 对于那些逻辑很复杂,循环嵌套比较深的程序,
     * 很有可能出现死循环,因此一定要采取一些预防措 施。
     * 限时测试是一个很好的解决方案。我们给这些测试函数设定
     * 一个执行时间,超过了这个时间,他们就会被系统强行终止,
     * 并且系统还会向你汇报该函数结束的原 因是因为超时,这样你就可以发现这些Bug了
     * 测试例子calculator中的squareRoot是个死循环。
     * */
     @Test(timeout = 1000)//单位为毫秒
     public void squareRoot() {
            calculator.squareRoot(4);
            assertEquals(2, calculator.getResult());
        }
     /*使用@Test标注的expected属性,将我们要检验的异常传递给他,
      * 这样JUnit框架就能自动帮我们检测是否抛出了我们指定的异常
      * */
     @Test(expected = ArithmeticException.class)
      public void divideByZero() {
         calculator.divide(0); 
         }
}
==============================================================

package andycpp;

import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/*
 * 对于参数测试需要重新写一个类, 而不能与其他测试共用同一个类,此例中我们定义了一个SquareTest类。
 * 然后,你要为这个类指定一个 Runner,而不能使用默认的Runner了,因为特殊的功能要用特殊的Runner嘛。
 * @RunWith(Parameterized.class)
 * 
 * */
@RunWith(Parameterized.class)
public class SquareTest {
    private static Calculator calculator = new Calculator();
    private int param;
    private int result;
    /*
     * 定义测试数据的集合,也就是上述的data()方法,
     * 该方法可以任意命名,但是必须使用@Parameters标注进行修饰。
     * 这个方法的框架就不予解释了,大家只需要注意其中的数据,是一个二维数组,
     * 数据两两一组,每组中的这两个数据,一个是参数,一个是你预期的结果
     * */
    @Parameters
    public static Collection date(){
        return Arrays.asList(new Object[][]{
            {2, 4},
            {0, 0},
            {-3, 9},
      });
    }
    
  //构造函数,对变量进行初始化

    
    //定义一个待测试的类,并且定义两个变量,一个用于存放参数,一个用于存放期待的结果。
    public SquareTest(int param, int result) {
           this.param = param;
           this.result = result;
    }
    
    @Test
    public void square() {
        calculator.square(param);
        assertEquals(result, calculator.getResult());
    }
    
}
==============================================================

package andycpp;
import org.junit.runner.RunWith;

import org.junit.runners.Suite;

 
/*
 * 大家可以看到,这个功能也需要使用一个特殊的Runner,
 * 因此我们需要向@RunWith标注传递一个参数Suite.class。
 * 同时,我们还需要另外一个标注@Suite.SuiteClasses,
 * 来表明这个类是一个打包测试类。我们把需要打包的类作为参数传递给该标注就可以了。
 * 有了这两个标注之后,就已经完整的表达了所有的含义,因此下面的类已经无关紧要,
 * 随便起一个类名,内容全部为空既可
 * */
@RunWith(Suite.class)

@Suite.SuiteClasses({

        CalculatorTest.class,

        SquareTest.class

        })
public class AllCalculatorTests {

}