JUnit4单元测试

前言:JUnit元数据

@Before:
使用了该元数据的方法在每个测试方法执行之前都要执行一次。
@After:
使用了该元数据的方法在每个测试方法执行之后要执行一次。
注意:@Before和@After标示的方法只能各有一个。这个相当于取代了JUnit以前版本中的setUp和tearDown方法,当然你还可以继续叫这个名字,不过JUnit不会霸道的要求你这么做了。
@Test(expected=*.class)
在JUnit4.0之前,对错误的测试,我们只能通过fail来产生一个错误,并在try块里面assertTrue(true)来测试。现在,通过@Test元数据中的expected属性。expected属性的值是一个异常的类型
@Test(timeout=xxx):
该元数据传入了一个时间(毫秒)给测试方法,
如果测试方法在制定的时间之内没有运行完,则测试也失败。
@ignore:
该元数据标记的测试方法在测试中会被忽略。当测试的方法还没有实现,或者测试的方法已经过时,或者在某种条件下才能测试该方法(比如需要一个数据库联接,而在本地测试的时候,数据库并没有连接),那么使用该标签来标示这个方法。同时,你可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。比如:@lgnore(“该方法还没有实现”),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。、

一、包含必要地Package

最主要地一个Package就是org.junit.*,把它包含进来之后,绝大部分功能就有了。还有一句话也非常地重要“import staticorg.junit.Assert.*;”,我们在测试的时候使用的一系列assertEquals方法就来自这个包。大家注意一下,这是一个静态包含(static),是JDK5中新增添的一个功能。也就是说,assertEquals是Assert类中的一系列的静态方法

二、测试类的声明

测试类是一个独立的类,没有任何父类。测试类的名字也可以任意命名,没有任何局限性。它与普通类的区别在于它内部的方法的声明

三、创建一个待测试的对象

你要测试哪个类,那么你首先就要创建一个该类的对象。

private staticCalculator calculator =newCalculator();

为了测试Calculator类,我们必须创建一个calculator对象。

四、测试方法的声明

在测试类中,并不是每一个方法都是用于测试的,你必须使用“标注”来明确表明哪些是测试方法。“标注”也是JDK5的一个新特性,用在此处非常恰当。我们可以看到,在某些方法的前有@Before、@Test、@Ignore等字样,这些就是标注,以一个“@”作为开头。这些标注都是JUnit4自定义的,熟练掌握这些标注的含义非常重要。

六、 忽略测试某些尚未完成的方法

七、 Fixture(暂且翻译为“固定代码段”)

Fixture的含义就是“在某些阶段必然被调用的代码”。“在任何一个测试执行之前必须执行的代码”就是一个Fixture,我们用@Before来标注它

一、 高级Fixture

两个Fixture标注,分别是@Before和@After,是否适合完成如下功能:有一个类是负责对大文件(超过500兆)进行读写,他的每一个方法都是对文件进行操作。换句话说,在调用每一个方法之前,我们都要打开一个大文件并读入文件内容,这绝对是一个非常耗费时间的操作。如果我们使用@Before和@After,那么每次测试都要读取一次文件,效率及其低下。这里我们所希望的是在所有测试一开始读一次文件,所有测试结束之后释放文件,而不是每次测试都读文件。JUnit的作者显然也考虑到了这个问题,它给出了@BeforeClass 和@AfterClass两个Fixture来帮我们实现这个功能。从名字上就可以看出,用这两个Fixture标注的函数,只在测试用例初始化时执行@BeforeClass方法,当所有测试执行完毕之后,执行@AfterClass进行收尾工作。在这里要注意一下,每个测试类只能有一个方法被标注为@BeforeClass或@AfterClass,并且该方法必须是Public和Static的。

二、 限时测试

那个求平方根的函数有Bug,是个死循环:

  public voidsquareRoot(intn) ...{

        for(; ;) ;//Bug : 死循环

  }

如果测试的时候遇到死循环,对于那些逻辑很复杂,循环嵌套比较深的程序,很有可能出现死循环,因此一定要采取一些预防措施。我们给这些测试函数设定一个执行时间,超过了这个时间,他们就会被系统强行终止,并且系统还会向你汇报该函数结束的原因是因为超时,这样你就可以发现这些Bug了。只需要给@Test标注加一个参数即可,代码如下:

  @Test(timeout = 1000)

  public voidsquareRoot() ...{

        calculator.squareRoot(4);

        assertEquals(2,calculator.getResult());

  }

  Timeout参数表明了你要设定的时间,单位为毫秒,因此1000就代表1秒。

三、 测试异常

经常会编写一些需要抛出异常的函数,如果一个函数应该抛出异常,但是它没抛出,当然是Bug。例如,我们写的计算器类有除法功能,如果除数是一个0,那么必然要抛出“除0异常”。因此,我们很有必要对这些进行测试。代码如下:

  @Test(expected = ArithmeticException.class)

  public void divideByZero() ...{

        calculator.divide(0);

  }

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

四、 Runner (运行器)

把测试代码提交给JUnit框架后,框架如何来运行代码呢?答案就是——Runner。在JUnit中有很多个Runner,他们负责调用测试代码,每一个Runner都有各自的特殊功能,要根据需要选择不同的Runner来运行测试代码。JUnit中有一个默认Runner,如果没有指定,那么系统自动使用默认Runner来运行你的代码。换句话说,下面两段代码含义是完全一样的:

import org.junit.runner.RunWith;

import org.junit.runners.Suite;

 

@RunWith(Suite.class)

@Suite.SuiteClasses({

MyTestCase.class, //测试类

PartSuite.class, //另一个测试套

})

public class AllTestCases {

}

  要想指定一个Runner,需要使用@RunWith标注,并且把你所指定的Runner作为参数传递给它。另外一个要注意的是,@RunWith是用来修饰类的,而不是用来修饰函数的。只要对一个类指定了Runner,那么这个类中的所有函数都被这个Runner来调用。

五、 参数化测试

一个对考试分数进行评价的函数,返回值分别为“优秀,良好,一般,及格,不及格”,因此你在编写测试的时候,至少要写5个测试,把这5中情况都包含了,这确实是一件很麻烦的事情。我们还使用我们先前的例子,测试一下“计算一个数的平方”这个函数,暂且分三类:正数、0、负数。测试代码如下:

importorg.junit.AfterClass;

  importorg.junit.Before;

  importorg.junit.BeforeClass;

  importorg.junit.Test;

  importstatic org.junit.Assert.*;

  public classAdvancedTest ...{

        private static Calculator calculator =new Calculator();

        @Before

        public void clearCalculator() ...{

               calculator.clear();

        }

        @Test

        public void square1() ...{

               calculator.square(2);

               assertEquals(4,calculator.getResult());

        }

        @Test

        public void square2() ...{

        calculator.square(0);

        assertEquals(0, calculator.getResult());

        }

        @Test

        public void square3() ...{

               calculator.square(-3);

               assertEquals(9,calculator.getResult());

        }

}

为了简化类似的测试,JUnit4提出了“参数化测试”的概念,只写一个测试函数,把这若干种情况作为参数传递进去,一次性的完成测试。代码如下:

  importstatic org.junit.Assert.assertEquals;

  importorg.junit.Test;

  importorg.junit.runner.RunWith;

  importorg.junit.runners.Parameterized;

  importorg.junit.runners.Parameterized.Parameters;

  importjava.util.Arrays;

  importjava.util.Collection;

  @RunWith(Parameterized.class)

  public classSquareTest{

  private static Calculator calculator = new Calculator();

        private int param;

        private int result;

        @Parameters

        public static Collection data(){

               return Arrays.asList(newObject[][]...{

               {2, 4},

               {0, 0},

               {-3, 9},

        });

  }

//构造函数,对变量进行初始化

六、断言和假设

断言:org.junit.Assert用于测试用例中,如果断言失败,用例即结束。

假设:org.junit.Assume用于在准备环境时判断环境是否符合要求,包括测试套的@BeforeClass,测试类的@BeforeClass,测试类的实例化,测试类的@Before。

如果假设失败,假设所处初始化代码方法立即结束,更深级别的后续工作也被忽略,相关测试用例被忽略,但与假设同级别的收尾工作还要继续执行。
例如:如果在测试类的@BeforeClass中假设失败,该类的实例化及子级别将被忽略,@AfterClass会继续执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值