Java单元测试-快速上手Junit(进阶)

时间:2022-12-31 05:10:27

基于Eclipse的单元测试框架Junit进阶

导言

在学习了上篇入门之后,如果你有所尝试,相信已经把持不住想要更高级的功能了,下面我们进入正题。(先把上次的简介部分放过来,因为这次会用到Before和After)

Junit简介

JUnit是一个Java语言的单元测试框架,应用它进行单元测试,能够准确、快速地保证程序基本模块的正确性。Junit通过注解的方式来识别测试方法,目前支持的主要注解有:

  • @BeforeClass:一次性setup,全局只执行一次,第一个运行
  • @AfterClass:一次性teardown,全局也只执行一次,最后一个运行
  • @Before:每次都在测试方法运行之前运行
  • @After:每次都在测试方法运行之后运行
  • @Test:测试方法

一个JUnit4的单元测试用例执行顺序为:
@BeforeClass -> @Before -> @Test -> @After -> @AfterClass,其中黑体部分可被多次执行。

添加Before&After

这个比较简单,只需要在新建测试程序的时候添加两个小选项就好,如图所示。

Java单元测试-快速上手Junit(进阶)

那么,这两个方法是做什么的呢?setUp()顾名思义,就是在每次测试开始之前要做的一些初始化工作,比如,清空队列、还原执行状态等;而tearDown()呢?也很容易理解,就是在某个testcase结束之后所做的一些回收、清除或者恢复工作。总之都是为了保证测试的高效进行。

测试异常处理

有时候我们的方法会抛出异常,那么测试的时候如果遇到会发现testcase显示为error,但是我们正是想让程序在某种情况下抛出异常,该如何处理呢?很简单,只需要添加一个expected就可以解决啦!


    @Test(expected = ArithmeticException.class)
    public void testDivideByZero(){
        cal.divide(0);
    }

这样,测试起来关于异常的error就可以消失不见了。

参数化测试

在某方法的分支较多、或者该方法的参数分很多情况、或者参数有较多特殊值,但是又需要较高的测试覆盖率时,我们就需要用到这种参数化的测试了,因为不然你的代码量会急剧飙升,而且会产生很多重复代码段,对于有程序洁癖的你是否能忍受呢?

我们还是举之前的例子,比如要测试乘方,我们也许会分3类测试:正数的平方,0的平方,负数的平方。如何参数化呢?


    package JunitTest;
    
    import static org.junit.Assert.*;
    
    import java.util.Arrays;
    import java.util.Collection;
    
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameters;
    
    @RunWith(Parameterized.class)
    public class ParaTest {
        private static Calculator Cal = new Calculator();
        private double para;    //parameter passed to method
        private double expcted; //expected result
        
        @Before
        public void setUp() throws Exception {
            Cal.clear();
        }
    
        @Parameters
        public static Collection db(){
            return Arrays.asList(new Object[][]{
                /*{para, expected}*/
                {-6, 36},
                {0, 0},
                {3, 9}
            });
        }
        
        public ParaTest(double para, double expected) {
            // TODO Auto-generated constructor stub
            this.para = para;
            this.expcted = expected;
        }
        
        @Test
        public void testSquare() {
            Cal.square(this.para);
            assertEquals(this.expcted, Cal.getResult(), 0.0001);
        }
    
    }

当然,这只是一个特例,在实际应用的时候不一定仅仅只有两个参数,也不一定一个参数是结果的期望值,总之灵活使用Collection中的东西就好,但切记,参数一定要按顺序书写,把握好db()和构造方法中的参数对应关系

那么,这段代码如何实现的呢?做如下分析:

  • 每一个参数化测试都要有自己的专属类,不能共用
  • 为此类指定Runner为ParameterizedRunner,通过在类的声明处添加@RunWith(Parameterized.class)修饰来实现
  • 在专属类中确定定义要使用的变量,该例有两个变量(para、expected)
  • Collection框架让测试数据组的处理标准化,用@Parameters对其修饰
  • 构造函数(constructor)的定义,保证与方法db()中参数的对应关系

限时测试

一般情况下,在测试时间过长、或者测试出现停滞状况时,我们都能够从JUnit的布局(layout)中看出来,从而定位到出现耗时较多(一般为死循环)的方法。所以该测试方式的作用主要体现在预防层面,而并非测试层面,这里就不赘述了。该方式可通过在注解@Test之后添加timeout来实现: @Test(timeout = 1000) ,注意此处的time单位为毫秒(ms)。


以上就是我学到的JUnit应用,之后会有覆盖率统计相关的更新。

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接(http://www.cnblogs.com/Echo-41/p/6921252.html)