单元测试更多的是在开发阶段完成,开发人员每写一个函数的时候都会写相应的单元测试。对于java代码,普遍使用的是jUnit,根据jUnit可以自己相应的开发一套自动化测试框架。这个的前提是要学会junit,先知道怎么用,才能知道怎么为我所用。

学习JUnit的操作很简单,JUnit是一个敏捷编程的开发框架,他的设计很值得学习。这也是我学习JUnit的原因。

JUnit最大的特点就是:各个方法之间是独立的,一个方法的失败不会影响另一个方法的执行。

JUnit 3:是基于反射机制的方法,有命名的约束,必须以test开头。每一个类都继承了TestCase类,而TestCase的父类是Assert类。即所有测试类都是TestCase类的子类。

JUnit 4:引入了注解(annotation),通过解析注解就可以为测试提供相应的信息。@Test表明这是要执行的测试方法,不管测试方法的名字是什么,都会执行。每一个类可以不继承任何类,可以是一个普通类也可以去继承一个类或实现一个接口,要实现测试只需要在要测试的方法之前加@Test注释就可以了,但是仍然可以直接使用断言,静态导入import static org.junit.Assert.*;

为了更好地理解junit测试用例,我找了一个简单的例子来练习:

例如有这么一个类Greeting,根据每天不同的时间来返回不同的问候语:

package com.test.one;

public class Greeting {
public static final String GREETING_MORNING = "Good Morning Sunshine!";
public static final String GREETING_AFTERNOON = "Just a few more hours before quiting time!";
public static final String GREETING_EVENING = "I am outta here";
public static final int MAX_HOUR_MORNING = 12;
public static final int MAX_HOUR_AFTERNOON = 17; private java.sql.Timestamp iGreetingTime = null; public Greeting(){
this(System.currentTimeMillis());
}
public Greeting(long greetingTime) {
super();
iGreetingTime = new java.sql.Timestamp(greetingTime);
}
public String getGreeting(){ if(iGreetingTime.getHours()<MAX_HOUR_MORNING){
return GREETING_MORNING;
}else if (iGreetingTime.getHours()<MAX_HOUR_AFTERNOON) {
return GREETING_AFTERNOON;
}else {
return GREETING_EVENING;
} } }

  

我们需要测试这个类,看是否可以根据时间的不同,来呈现不同的问候语。创建junit的测试用例需要遵循一下几点:

1、Junit类需继承TestCase

2、setUp()和setDown()为每个方法准备或销毁测试装备

3、创建public的方法,方法名为test开头,如testMorningGreeting(),使用assert判断实际返回的值和期望值

4、super(testMethod)为每个测试方法生成实例。首先执行setUp(),然后执行testMethod ,最后执行tearDown()。

package com.test.test;

import java.sql.Time;

import com.test.one.Greeting;

import junit.framework.TestCase;

public class GreetingTest extends TestCase {

    protected void setUp() throws Exception {
super.setUp();
} protected void tearDown() throws Exception{
super.tearDown();
} public void testMorningGreeting() throws Exception {
Time time = new Time(9, 0, 0);
Greeting greeting = new Greeting(time.getTime());
assertEquals("the morning greeting expected", Greeting.GREETING_MORNING, greeting.getGreeting());
}
public void testAfternoonGreeting() throws Exception {
Time time = new Time(12, 0, 0);
Greeting greeting = new Greeting(time.getTime());
assertEquals("the Afternoon greeting expected", Greeting.GREETING_AFTERNOON, greeting.getGreeting());
}
public void testEveningGreeting() throws Exception {
Time time = new Time(18, 0, 0);
Greeting greeting = new Greeting(time.getTime());
assertEquals("the Evening greeting expected", Greeting.GREETING_EVENING, greeting.getGreeting());
} public GreetingTest(String testMethod){
super(testMethod);
}
}

这个只是单个测试用例,junit也提供了测试套件组织想要执行的测试用例。

如果你已经有了两个测试用例,AddJobCmdImpTest、RemoveJobCmdImpTest等TestCase的子类别,如果想一次运行这两个测试,需要使用AllTest的类,代表一个测试套件。

public class AllTest {
public static Test suite(){
TestSuite suite = new TestSuite("Test for XXXX");
suite.addTest(new TestSuite(AddJobCmdImpTest.class));
suite.addTest(new TestSuite(RemoveJobCmdImpTest.class));
return suite;
}
}

以下是JUnit4的代码:

public class GreetingTest extends TestCase {

    @Before
public void setUp() throws Exception {
super.setUp(); }
@After
public void tearDown() throws Exception{
super.tearDown();
}
@Test
public void ttrestMorningGreeting() throws Exception {
Time time = new Time(9, 0, 0);
Greeting greeting = new Greeting(time.getTime());
assertEquals("the morning greeting expected", Greeting.GREETING_MORNING, greeting.getGreeting());
}
@Test
public void testAfternoonGreeting() throws Exception {
Time time = new Time(12, 0, 0);
Greeting greeting = new Greeting(time.getTime());
assertEquals("the Afternoon greeting expected", Greeting.GREETING_AFTERNOON, greeting.getGreeting());
}
@Test
public void testEveningGreeting() throws Exception {
Time time = new Time(18, 0, 0);
Greeting greeting = new Greeting(time.getTime());
assertEquals("the Evening greeting expected", Greeting.GREETING_EVENING, greeting.getGreeting());
}
}
 

关于JUnit4的一些知识点:

1)、注释

 注释  说明
@Before

用于方法注释,表示该方法在每个测试方法执行前执行一次,可用于一些初始工作

@BeforeClass 用于方法注释,该方法在所有测试方法运行前运行,且只运行一次,添加该注释的方法必须修饰为 public static void 且没有参数。
@Test

方法注释,表示测试方法。该方法有两个属性

a: expected :该属性表示测试方法必须抛出一个异常,且异常的类型必须是该属性要求的类型,否则表示测试方法失败。也叫做异常测试。 例如:@Test(expected=IndexOutOfBoundsException.class)

b:timeout 用于超时测试,表示该测试方法的执行时间如果超过了要求的时间则失败 单位为毫秒

例如:@Test(timeout=100)

@Ignore 方法注释,表示会被忽略的测试方法
@After

方法注释,被注释的方法会在每个测试方法执行完成之后执行一次,如果其它的方法抛出了异常,该方法同样会被执行。主要用于释放在@Before方法中初始化的资源。

@AfterClass

方法注释,功能同@After,只不过是该方法释放的是@BeforeClass方法

初始化的资源。且在所有的测试方法执行完成之后,只执行一次。

一个JUnit 4 的单元测试用例执行顺序为:

@BeforeClass –> @Before –> @Test –> @After –> @AfterClass

2)、failure 和error

failure:是由于预期的结果和实际运行结果不同而导致的,例如当使用assertEqual()或其它assertXXX()方法断言失败时,就会报出failure,如果发现failure,你就要去检查你的测试方法或者是被测试方法中的填写的逻辑是否有误。简单点,就是预想到的。

error:是填写程序是没有考虑到的问题,在执行测试的断言之前,程序就因为某种类型的意外而停止,比如说我们在操作数组的时候,因为存取超出索引就会引发ArrayIndexOutOfBoundsException,这时程序就会报error,程序将无法运行下去,提前结束,这个时候就要检查被测试方法中是否由欠缺考虑的地方。简单点,就是预想不到的,没有执行到断言。

JUnit4是JUnit框架有史以来的最大改进,其主要目标便是利用Java5的Annotation特性简化测试用例的编写。Annotation翻译成元数据。元数据是什么?元数据就是描述数据的数据。也就是说,这个东西在Java里面可以用来和public、static等关键字一样来修饰类名、方法名、变量名。修饰的作用描述这个数据是做什么用的,差不多和public描述这个数据是公有的一样。

@Test(expected=*.class)
在JUnit4.0之前,对错误的测试,我们只能通过fail来产生一个错误,并在try块里面assertTrue(true)来测试。现在,通过@Test元数据中的expected属性。expected属性的值是一个异常的类型

@Test(timeout=xxx):
该元数据传入了一个时间(毫秒)给测试方法,
如果测试方法在制定的时间之内没有运行完,则测试也失败。

@ignore:
该元数据标记的测试方法在测试中会被忽略。当测试的方法还没有实现,或者测试的方法已经过时,或者在某种条件下才能测试该方法(比如需要一个数据库联接,而在本地测试的时候,数据库并没有连接),那么使用该标签来标示这个方法。同时,你可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。比如:@lgnore(“该方法还没有实现”),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。

@RunWith(Parameterized.class) 参数化测试。

你可能遇到过这样的函数,它的参数有许多特殊值,或者说他的参数分为很多个区域。比如,一个对考试分数进行评价的函数,返回值分别为“优秀,良好,一般,及格,不及格”,因此你在编写测试的时候,至少要写5个测试,把这5中情况都包含了,这确实是一件很麻烦的事情。只写一个测试函数,把这若干种情况作为参数传递进去,一次性的完成测试。

@RunWith(Parameterized.class)

public class SquareTest ...{

private static Calculator calculator = new Calculator();

  private int param;

private int result;

@Parameters

public static Collection data() ...{

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());

}

}

下面我们对上述代码进行分析。首先,你要为这种测试专门生成一个新的类,而不能与其他测试共用同一个类,此例中我们定义了一个SquareTest类。然后,你要为这个类指定一个Runner,而不能使用默认的Runner了,因为特殊的功能要用特殊的Runner嘛。@RunWith(Parameterized.class)这条语句就是为这个类指定了一个ParameterizedRunner。第二步,定义一个待测试的类,并且定义两个变量,一个用于存放参数,一个用于存放期待的结果。接下来,定义测试数据的集合,也就是上述的data()方法,该方法可以任意命名,但是必须使用@Parameters标注进行修饰。这个方法的框架就不予解释了,大家只需要注意其中的数据,是一个二维数组,数据两两一组,每组中的这两个数据,一个是参数,一个是你预期的结果。比如我们的第一组{2, 4},2就是参数,4就是预期的结果。这两个数据的顺序无所谓,谁前谁后都可以。之后是构造函数,其功能就是对先前定义的两个参数进行初始化。在这里你可要注意一下参数的顺序了,要和上面的数据集合的顺序保持一致。如果前面的顺序是{参数,期待的结果},那么你构造函数的顺序也要是“构造函数(参数, 期待的结果)”,反之亦然。

打包测试

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

@RunWith(Suite.class)

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

public class AllCalculatorTests ...{}

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

JUnit单元测试--小试牛刀的更多相关文章

  1. junit单元测试(keeps the bar green to keeps the code clean)

    error是程序错误,failure是测试错误. junit概要: JUnit是由 Erich Gamma (设计模式的创始人)和 Kent Beck (敏捷开发的创始人之一)编写的一个回归测试框架( ...

  2. spring && Cobertura && maven &&junit 单元测试以及测试覆盖率

    1. 目的:       junit 单元测试,Cobertura   测试覆盖率报告       项目目录结构          2. maven 配置     <project xmlns= ...

  3. 解决Junit单元测试 找不到类 ----指定Java Build Path

    做junit 单元测试时,发现怎么执行都是以前编译过得代码. 最后找到原因了, src/test/java 编译完的.class路径是 Default output folder Default ou ...

  4. JUnit单元测试框架的使用

    http://blog.csdn.net/mao520741111/article/details/51462215 原文地址 http://www.open-open.com/lib/view/op ...

  5. Java 工具 JUnit单元测试

    Java 工具 JUnit单元测试 @author ixenos 1.1.   JUnit单元测试框架的基本使用 一.搭建环境: 导入junit.jar包(junit4) 二.写测试类: 0,一般一个 ...

  6. Spring框架中整合JUnit单元测试的方法

    一. 步骤: 1. 拷贝jar包: 1. JUnit-4.9.jar和spring-test-4.2.4.RELEASE.jar ; 2. 替换原来的main函数: 1. 在测试类上使用注解方式替换: ...

  7. spring框架学习(三)junit单元测试

    spring框架学习(三)junit单元测试 单元测试不是头一次听说了,但只是听说从来没有用过.一个模块怎么测试呢,是不是得专门为一单元写一个测试程序,然后将测试单元代码拿过来测试? 我是这么想的.学 ...

  8. 备忘:Junit单元测试

    junit 目前测试都是在main方法中调用目前的结果都需要人工对比是否是想要的 1.使用Junit测试方法,绿色条条代表方法测试成功,没有bug,如果是红色条条代表有异常,测试不通过2.点击方法名. ...

  9. 单元测试系列:JUnit单元测试规范

    更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6762032.html Junit测试代 ...

随机推荐

  1. HDFS命令行操作

    启动后可通过命令行使用hadoop. (1)所有命令 (先将$HADOOP_HOME/bin加入到.bashrc的$PATH变量中) [html] view plaincopy [hadoop@nod ...

  2. SQL随机数的生成

    下面是一个随机函数问题,获取两位数的随机数,且不重复. 但是说明一下,这个函数有点bug,例如:两位数的函数最后能生成89个,如果将数量改成90,那么就无法生成,陷入死循环了. IF object_i ...

  3. hive 操作(转)

    1.命令行操作 (1)打印查询头,需要显示设置: set hive.cli.print.header=true; (2)加"--",其后的都被认为是注释,但 CLI 不解析注释.带 ...

  4. 从零开始学ios开发(十二):Table Views(中)UITableViewCell定制

    我们继续学习Table View的内容,这次主要是针对UITableViewCell,在前一篇的例子中我们已经使用过UITableViewCell,一个默认的UITableViewCell包含imag ...

  5. Aspose 数字和日期 设置

    Microsoft Excel一个非常强大的功能就是使客户可以设置数字和日期的显示格式,众所周知数字可以显示为不同的值格式,包含:小数.货币.百分数.分数.账面价值等,同样地Aspose.Cells也 ...

  6. OC类的本质,深入探讨,load方法和initialize方法

    1:类的本质:类也是一种类,可以叫做类类,类对象,类类型: 2:类和对象在内存中分配问题(注意区分类的对象和类对象的概念) 类对象在内存中只有一份,且只加载一次,类对象中存放了类中定义的方法: 而成员 ...

  7. Halcon学习笔记之缺陷检测(二)

    例程:detect_indent_fft.hdev 说明:这个程序展示了如何利用快速傅里叶变换(FFT)对塑料制品的表面进行目标(缺陷)的检测,大致分为三步: 首先,我们用高斯滤波器构造一个合适的滤波 ...

  8. AvalonDock 2.0+Caliburn.Micro+MahApps.Metro实现Metro风格插件式系统(菜单篇)

    这章主要说插件的菜单,可以说菜单是最核心的部分,前面我们已经实现了Document添加,现在主要就是生成具有层级关系的菜单,以及把菜单跟我们自定义的Document关联起来,也就是MenuPart-& ...

  9. android button 字母自动大写

    <Button android:id="@+id/btnStart" android:layout_width="wrap_content" androi ...

  10. sqlserver 类似oracle的rownum功能: row_number

    select row_number() over(order by t.id ) as num,id,name from (SELECT distinct [列 0] as id ,[列 1] as ...