Junit单元测试框架是Java程序开发必备的测试利器,现在最常用的就是Junit4了,在Junit4中所有的测试用例都使用了注解的形式,这比Junit3更加灵活与方便。之前在公司的关于单元测试的培训课程中,讲师仅仅讲述了Junit4的基本的与生命周期相关的注解的使用,主要包括@BeforeClass、@Before、@Test、@After、@AfterClass这些注解,这些在应付普通简单的单元测试已经足够,然而有很多更加复杂且也会经常遇到的测试需求依靠这些生命周期注解并不能完成!因此这篇分享将为您呈现Junit4的另一片新大陆,且看陈述…

其实,在单元测试培训课程中,讲师并没有讲到Junit4的核心,例如为什么Junit没有main()方法就能运行(因为我们知道无论是什么程序都必须得有一个程序入口,而它通常是main);在例如Junit的核心组成部分是什么?如何更改Junit在运行单元测试时获取数据和执行测试的行为?更具体一点,如果我要为一个需要两个参数的方法进行测试,如何使用我所提供的参数的所有排列组合对方法进行测试?如果我需要在茫茫的测试用例中只测试与特定类相关的用例该怎么做…….

在这之前,先纠正一点------Junit4可以直接运行我们的某个方法,没有main入口函数是断然不行的。正如我之前给我们组的一个妹子讲Spring的时候告诉她,在测试方法中,对测试方法所在的类添加Spring的 (Compent注解或者为该类的成员变量添加)Resource注解并没有什么卵用,即Spring根本不会来扫描这个测试类,更不会为这个类注入属性值。为什么这么说呢?因为Spring是在测试类中由被@Before标注的方法所启动的,这时候,JVM已经将此测试类实例化了,而这并不是由Spring实例化的,Spring晚了一步,所以在Spring的容器中并没有此类的实例。那么Junit4真的有main方法吗?没错,既然它能直接运行我们的方法,那它必然自己为JVM提供了程序入口。其实在org.junit.runner包下,有个JUnitCore.class,其中就有一个 标准的main方法,这就是JUnit入口函数。如此看来,它其实和我们直接在自己的main方法中跑我们要测试的方法在本质上是一样的。

接下来,我要说的就是Junit测试框架的新大陆,或者说是其核心组件,也正是讲师所没有讲到但却十分有用的东西------Runner,即Junit的运行器!

Runner只是一个抽象类,表示用于运行Junit测试用例的工具,通过它可以运行测试并通知Notifier运行的结果。通常我们可以在待测方法所在的类之上使用@RunWith注解来为这个测试类指定一个特定的Runner。不过在很多情况下,我们并没有这么做,那是因为,我们使用了Junit的默认Runnner------BlockJunit4ClassRunner。当我们不为测试类添加@RunWith注解的时候,其实使用的就是这个Runner,它作为默认Runner只为我们提供了基本的基于Junit生命周期的测试注解。而有更多非常规的测试需求,则需要我们为测试类添加@RunWith注解并指定特定的Runner来完成!下面列出一些比较有用的Runner。

一、Suit------它可以一次生执行全面在多个类中的测试用例,例如:

@RunWith(Suite.class)
@SuiteClasses({Person.class, People.class})
public class TestSuitMain{
//虽然这个类是空的,但依然可以运行Junit测试,运行时,它会将Person.class和//People.class中的所有测试用命都执行一遍!
}

二、Parameterized------在普通的单元测试中被@Test注解标注的测试方法只能是public void的,且不能有任何输入参数。而这时常会给我们造成困扰,因为有时候我们需要为测试方法输入参数,甚至是批量指定多个待测参数。这时Parameterized这个Runner就能满足我们的要求,用法如下:

@RunWith(Parameterized.class)
public class TestGenerateParams{
private String greeting;
public TestGenerateParams(String greeting){
super();
this.greeting = greeting;
}
@Test
public void testParams(){ System.out.println(greeting);
} /**
* 这里的返回的应该是一个可迭代数组,且方法必须是public static
* @return
*/
@Parameters
public static List getParams(){
return Arrays.asList(new String[][]{{"hello"},{"hi"},{"good morning"},{"how are you"}});
}
}

三、Category------继承自Suit,更强大,它可以让我们对测试类中被测试的方法进行分类执行,例如Person对象具有一些属性,这些属性拥有get/set方法,同时还有一些普通方法。我们可以将获取属性的get方法和普通方法进行分类测试。如:

public class PersonTest{
@Category(AttributeFun.class)
@Test
public void testGetAge(){
int age = person.getAge();
assertEquals(3, age);
}
@Category(AttributeFun.class)
@Test
public void testGetName(){
String name = person.getName();
assertEquals("Willard", name);
}
@Category(BehaviorFun.class)
@Test
public void testTalk(){
String message = person.talkTo("Jimy");
assertNotNull(message);
}
@Category(BehaviorFun.class)
@Test(timeout=200)
public void testWalk(){
person.walk();
}
} //对应的测试执行代码如下:
@RunWith(Categories.class)
@SuiteClasses(PersonTest.class)
@IncludeCategory(AttributeFun.class)
public class CategoryTest{
//注意,如果不加@IncludeCategory注解,那么就和使用Suit具有一样的效果了。
}

四、Theories------虽意为原理或推测的意思,但我在这里以更直观的方式表述它:提供一组参数的排列组合值作为待没方法的输入参数。同时注意到在使用Theories这个Runner的时候,我们的待测方法可以拥有输入参数,而这在其它的Runner中的测试方法是不成的。下面是一个例子:

@RunWith(Theories.class)public class TheoriesTest{
@DataPoint
public static String nameValue1 = "Tony";
@DataPoint
public static String nameValue2 = "Jim";
@DataPoint public static int ageValue1 = 10;
@DataPoint
public static int ageValue2 = 20;
@Theory
public void testMethod(String name, int age){
System.out.println(String.format("%s's age is %s", name, age));
}
}

上面的代码的意思是,将”Tony”、”Jim”、10、20四个参数以类型合法的排列组合传给待没方法。因此输出的结果必然也有2x2=4种:

Tony's age is 10

Tony's age is 20

Jim's age is 10

Jim's age is 20

不过,为了简单,我们除了可以使用@DataPoint注解来提供参数之外,还可以通过@DataPoints注解来提供参数,参照上述代码,只需要将@DataPoint注解标注的四个字段参数替换为如下的两个即可:

@DataPoints
public static String[] names = {"Tony", "Jim"};
@DataPoints
public static int[] ageValue1 = {10, 20};

上展示了四个Junit运行器的使用示例,有这个四个运行器的支持,基本上大部分的测试需求得可以得到解决。当然Junit提供的功能远不止这些。除此之外,我们还可以使用Junit4提供的Rule/Assume/Assert等。

其中使用Rule可以为单元测试指定测试规则,下面展示了这些可用的Rule:

Verifier: 验证测试执行结果的正确性。

ErrorCollector: 收集测试方法中出现的错误信息,测试不会中断,如果有错误发生测试结束后会标记失败。

ExpectedException: 提供灵活的异常验证功能。

Timeout: 用于测试超时的Rule。

ExternalResource: 外部资源管理。

TemporaryFolder: 在JUnit的测试执行前后,创建和删除新的临时目录。

TestWatcher: 监视测试方法生命周期的各个阶段。

TestName: 在测试方法执行过程中提供获取测试名字的能力。

此外,Assume表示假设,但它实际是对待没方法的参数进行合法性校验的,如果校验不合格则直接抛异常,而不执行测试。这和Guava中的Predictions类似。Assume提供的校验规则如下:

assumeTrue/assumeFalse、 assumeNotNull、 assumeThat、 assumeNoException

例如:(通过下述代码也可以看到,要使用参数,则应使用@Theory注解)

@Theory
public void printAge(String name, int age){
Assume.assumeTrue(age > 0);//如果参数age<=0,会抛AssumptionViolatedException异常
System.out.println(String.format("%s's Name is %s.", name, age));
}

Assert是Junit提供的断言,与Assume不同,Assert是对测试结果的校验,它提供的检验规则如下:

AssertTrue、AssertFalse:结果的true、false。

AssertThat:使用Matcher做自定义的校验。

AssertEquals、AssertNotEquals:判断两个对象是否相等。

AssertNull、AssertNotNull:判断对象是否为空。

AssertSame:判断两个对象是否为同一个,不同于equals这里是使用“==”判断。

AssertArrayEquals:判断两个数组是否相等。

Junit4单元测试之高级用法的更多相关文章

  1. Java基础学习总结(24)——Java单元测试之JUnit4详解

    Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法.目前支持的主要注解有: @BeforeClass 全局只会执行一次,而且是第一个运行 @Before  ...

  2. react第七单元(组件的高级用法-组件的组合(children的用法)-高阶组件-封装组件)

    第七单元(组件的高级用法-组件的组合(children的用法)-高阶组件-封装组件) #受控组件 简而言之,就是受到状态state控制的表单,表单的值改变则state值也改变,受控组件必须要搭配onc ...

  3. redis(二)高级用法

    redis(二)高级用法 事务 redis的事务是一组命令的集合.事务同命令一样都是redis的最小执行单元,一个事务中的命令要么执行要么都不执行. 首先需要multi命令来开始事务,用exec命令来 ...

  4. 玩转单元测试之Testing Spring MVC Controllers

    玩转单元测试之 Testing Spring MVC Controllers 转载注明出处:http://www.cnblogs.com/wade-xu/p/4311657.html The Spri ...

  5. 使用VisualStudio进行单元测试之二

    借着工作忙的借口,偷了两天懒,今天继续单元测试之旅.前面说了如何进行一个最简单的单元测试,这次呢就跟大家一起来熟悉一下,在visual studio中如何进行数据驱动的单元测试. 开始之前先来明确一下 ...

  6. 补习系列(8)-springboot 单元测试之道

    目录 目标 一.About 单元测试 二.About Junit 三.SpringBoot-单元测试 项目依赖 测试样例 四.Mock测试 五.最后 目标 了解 单元测试的背景 了解如何 利用 spr ...

  7. Junit4单元测试的基本用法

    看了一些Junit4的视频,简单了解了Junit4的一些基本用法,整理记录一下. 环境搭建 这里使用的开发工具是MyEclipse,首先新建一个Java工程,将Junit4的jar包引入,eclips ...

  8. API Test Postman接口测试之高级篇1

    API Test  Postman接口测试之高级篇1 一.postman中的请求参数简介: 1.请求参数简介: 点击params下面会出现key,value等信息,这里填写的会自动追加在url地址后面 ...

  9. Ecplise中Junit4单元测试的基本用法

    看了一些Junit4的视频,简单了解了Junit4的一些基本用法,整理记录一下. 环境搭建 这里使用的开发工具是MyEclipse,首先新建一个Java工程,将Junit4的jar包引入,eclips ...

随机推荐

  1. Hook SSDT中NtCreateProcessEx

    #ifdef __cplusplus extern "C" { #endif #include <ntddk.h> #ifdef __cplusplus } #endi ...

  2. touch事件分发

    touch事件分发 IOS事件分发 我们知道,如果要一个view(就是view,不是UIControl控件)能够响应事件操作,通常的做法是给该View加上相应的手势,或者重写和touch(当然也可以是 ...

  3. easyui struts后台实现tree返回json数据

    首先jsp页面有一ul用于展现tree <ul id="trueULid"></ul> 加载tree <script type="text/ ...

  4. Redis:在windows环境安装Redis

    Redis:在windows环境安装Redis 第一步: 下载windows版本的Redis:https://github.com/MSOpenTech/Redis. 第二步: 在命令行执行:D:\r ...

  5. Nunit NMock Ncover单元测试

    Nunit中如何进行事务性单元测试   单元测试要求:单元测试方法并不真正去变更数据库,也就是说单元测试不依赖于数据库中的数据.那我们如何解决执行单元测试方法后,不变更数据库中数据呢? 一般的解决方案 ...

  6. jquery跨域请求数据

    jquery跨域请求数据 jquery跨越请求数据.实际开发中经常会碰到两个网站数据交互问题,当向另一个站点请求数据该如何做? 实际上非常容易,请按照下面的步骤做: 第一:编写js,通过get获取远程 ...

  7. cocos2d(x) HTML label ;CCHTML CCHTMLLabel

    这几天由于特殊需要,写了一个HTMLLabel.可以直接支持HTML的几种格式,<font> <a href> color size 等等. 参考object C的一个ios开 ...

  8. easyui 个人使用心得之下拉列表

    下拉框: 第一种:从数据库获取<input id="FlowType" name="FlowType" style="width: 245px; ...

  9. .NET基础——ASSCII码表

    char类型不能直接强转为int32,因为强转后的结果是去ascii码表的值.如char 类型的1,强转为int32后的值是49. 要得到正确的结果,现将char类型转换为string类型,再转为in ...

  10. OpenH264

    转自:http://blog.csdn.net/chinabinlang/article/details/41209053 目前最常用的264工程师x264: 最近有又有一个开源工程OpenH264, ...