基于Feed4JUnit架构的单元测试技术研究与应用

2014-09-24 12:09杨鹏
软件工程 2014年7期
关键词:单元测试测试数据套件

杨鹏

摘要:软件测试技术在软件质量控制过程中一直起着非常重要的作用。JUnit是被广泛应用的Java单元测试框架,主要测试基于java语言编写的程序代码,用于编写和运行可重复的测试。Feed4JUnit是开源的基于JUnit的扩展,通过使用Feed4JUnit提供的注释,用户可以很方便地把测试数据存放在文件或其他数据源。本文分析了应用Feed4JUnit进行单元测试的方法,并通过实际开发示例实现数据与代码分离的测试。

关键词:Feed4JUnit架构;单元测试;数据源

中图分类号:TP311.52 文献标识码:A

Research on Unit Testing Technology Based on Feed4JUnit Architecture

YANG Peng

(School of Information Engineering Guangzhou Panyu Polytechnic,Guangzhou 511483,China)

Abstract:Software testing technology has been under the control of software processto use is very important.Unit is the Java unit test framework is widely used,mainly used for testing the class and method based on the Java language,Feed4JUnit is the extension of JUnit based on open source, using the Feed4JUnit annotation,the usercan be very convenient to test the data stored in a file or other data source.This paperanalyzes the application of Feed4JUnit unit test methods,and through the actualexample of developing,realize the separation of data and code test.

Keywords:Feed4JUnit;unit test;data source

1 引言(Introduction)

单元测试(Unit Testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数[1],Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块[2]。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试[3]。单元测试不仅仅保证代码在方法级别的正确性,它还能改进设计,易于对代码重构[4]。凡是容易编写单元测试的代码,往往是优秀的设计和松耦合的组件,凡是难于编写单元测试的代码,往往是设计不佳和耦合度高的系统[5]。因此,编写单元测试不仅仅是掌握单元测试柜架的用法,更重要的是在编写单元测试的过程中发现设计缺陷,改进系统结构,从而实现良好的可扩展性。

任何一个项目,单元测试应该在详细设计之后开始进行,首先根据详细设计文档进行单元测试用例的编写,编写完成后进行代码开发,代码完成后运行单元测试,如果通过,则该方法可以发布运行,如果不通过需要进行代码改造,再进行单元测试,直到单元测试运行通过为止。

2 Junit单元测试架构(Junit unit test framework)

JUnit是由Erich Gamma和Kent Beck编写的一个回归测试框架(Regression Testing Framework)。Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit是一套框架,继承TestCase类,就可以用Junit进行自动测试了。通常来说,在极限编程中,基本过程是这样的:构思→编写测试代码→编写代码→测试,而且编写测试和编写代码都是增量式的,写一点测一点,在编写以后的代码中如果发现问题可以较快的追踪到问题的原因,减小回归错误的纠错难度,如图1所示的是Junit基本架构。

图1 Junit基本架构

Fig.1 The basic architecture of Junit

在Junit类中,有很多定义类。Test:是TestCase、TestSuite的共同接口。run(TestResult)用来运行Test,并且将结果保存到TestResult。TestCase:Test的接口的抽象实现,是Abstract类,所以不能实例化,能被继承。其中一个构造函数TestCase(String Name),根据输入的参数,创建一个测试实例。参数为该类的以test开头的方法名,把它添加到TestSuite中,指定仅仅运行TestCase中的一个方法。

TestSuite:实现Test接口。可以组装一个或者多个TestCase。待测试类中可能包括了对被测类的多个TestCase,而TestSuit可以保存多个TestCase,负责收集这些测试,这样就可以一个Suite就能运行对被测类的多个测试。TestResult:保存TestCase运行中的事件。TestResult有ListfFailures和ListfErrors。fFailures记录Test运行中的AssertionFailedError,而fErrors则记录Exception。Failure是当期望值和断言不匹配的时候抛出的异常,而Error则是不曾预料到的异常,如:ArrayIndexOutOfBoundsException。TestListener:是个接口,对事件监听,可供TestRunner类使用。

ResultPrinter:实现TestListener接口。在TestCase运行过程中,对所监听的对象的事件以一定格式及时输出,运行完后,对TestResult对象进行分析,输出的统计结果。BaseTestRunner:所有TestRunner的超类。java Junit.swingui.TestRunner:实BaseTestRunner,提供图形界面。java Junit.textui.TestRunner:实现BaseTestRunner,提供文本界面。下面将以它做为例子讲解JUnit生命周期。

3 JUnit4测试实例(JUnit4 test examples)

在应用程序的业务逻辑中存在大量的这样的接口:他们接受不同的输入,然后进行或验证、或处理,进而完成相同的流程。比如网站的登录入口,用户名和密码都有长度的限制,同时也具有是否允许特殊字符的限制等,所以在我们进行其单元测试的过程中,根据不同长度的用户名和密码,以及不同的字符组合,只需要提供相同的测试代码结构,就能完成测试,不同的仅仅测试数据与期望值,但是因为每一个测试方法中的输入参数不同,我们必须为每一个输入组编写单独的测试用例,从而产生大量冗余代码,十分不便于维护。

将Java对象名称(每个单词的头字母大写)按照数据库命名的习惯进行格式化,格式化后的数据为小写字母,并且使用下划线分割命名单词,要求对输入数据进行非法验证。

首先新建一个TestJUnit。打开项目TestJUnit的属性页→选择“Java Build Path”子选项→点选“Add Library…”按钮→在弹出的“Add Library”对话框中选择JUnit(图2),并在下一页中选择版本4.1后点击“Finish”按钮。

图2 JUnit 运行测试界面

Fig.2 JUnit run the test interface

在JUnit运行界面提示有两个测试情况未通过,当首字母大写时得到的处理结果与预期的有偏差,造成测试失败;而当测试对 null的处理结果时,则直接抛出了异常,测试错误。

JUnit将测试失败的情况分为两种:failure和error。Failure一般由单元测试使用的断言方法判断失败引起,它表示在测试点发现了问题;而error则是由代码异常引起,这是测试目的之外的发现,它可能产生于测试代码本身的错误(测试代码也是代码,同样无法保证完全没有缺陷),也可能是被测试代码中的一个隐藏的bug。显然,被测试代码中并没有对首字母大写和null这两种特殊情况进行处理,现在对源代码进行修改,添加对这两种情况的处理,代码如下:

package sample.test;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;

import java.util.Collection;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.junit.runners.Parameterized;

import org.junit.runners.Parameterized.Parameters;

import sample.code.UserAccess;

/*

* JUnit - Parameter test sample

*/

@RunWith(Parameterized.class)

public class JunitSample {

private String user;

private String pw;

private boolean expected;

@Parameters

public static Collection dataGenerater() {

return Arrays.asList(new Object[][] {

{ "user01", "123456", true },

{ "helloworld", "123456", false },

{ "david", "re*ads", false },

{ "goodone", "onegood", true } });

}

public JunitSample(String user, String pw, boolean expected) {

this.user = user;

this.pw = pw;

this.expected = expected;

}

@Test

public void testAccessCheck() {

assertEquals(expected, UserAccess.accessCheck(user, pw));

}

}

运行测试,显示的测试结果如图3所示。

图3 测试结果

Fig.3 The test results

通过以上代码可以看出,JUnit4通过使用一个标记@Parameters注释的返回类型为Collection的静态方法产生数据,测试数据通过变量传递给测试方法,从而完成多数据输入的测试。但是随着业务的需要,测试人员需要经常增加测试数据与修改现有测试数据,JUnit4提供的硬编码方式已经愈显笨重和不便,数据与代码分离显得尤为重要。

本文所述的Feed4Junit可以良好 地解决数据与代码分离的问题,Feed4JUnit是JUnit测试框架的扩展,它通过操作来自于文件以及不同的数据源的测试数据,使单元测试变得更容易编写与维护。本文通过实例展示Feed4JUnit的安装以及测试代码与数据分离的实现,本文的实例代码全部基于针对如下一个简单的用户登录检验的类。

package sample.code;

public class UserAccess {

// simple validation for user name and password

public static boolean accessCheck(String userName, String password) {

if (userName.length() <= 4 || userName.length() > 8)

return false;

if (password.length() <= 4 || password.length() > 8)

return false;

if (userName.contains("@"))

return false;

if (password.contains("*"))

return false;

return true;

}

}

在静态方法excel中,本文采用二维数组的方式来构建测试所需要的参数列表,其中每个数组中的元素的放置顺序并没有什么要求,只要和构造函数中的顺序保持一致就可以了。现在如果再增加一种测试情况,只需要在静态方法excel中添加相应的数组即可,不再需要复制粘贴出一个新的方法出来了。

随着项目的进展,项目的规模在不断地膨胀,为了保证项目的质量,有计划的执行全面的单元测试是非常有必要的。但单靠JUnit提供的测试套件很难胜任这项工作,因为项目中单元测试类的个数在不停的增加,测试套件却无法动态的识别新加入的单元测试类,需要手动修改测试套件。

4 结论(Conclusion)

本文主要介绍了Junit相关单元测试技术,分析了应用Feed4JUnit进行单元测试的方法,用户可以方便的把测试数据存放在文件或其它数据源。通过提供简单的注释,Feed4JUnit使用户能够极其方便的实施数据与代码分离的测试,极大地增强了JUnit测试框架的易用性。本文所叙述的仅仅是Feed4JUnit提供的测试增强功能的一部分,Junit4同时还提供了大量数据的随机测试和等价类测试等众多功能。

参考文献(References)

[1] 高共革,杨静.基于.NET的单元测试自动化方法研究[J].微计算机信息,2008,24(19):280-281.

[2] 吴高峡,王芙蓉.单元测试的自动化实践[J].计算机与数字工程,2007,35(1):174-176.

[3] 吴继娟,孙媛媛,刘桂艳.基于BIST的FPGA逻辑单元测试方法[J].哈尔滨工业大学学报,2004,36(8):1074-1076.

[4] 严俊,等.JUTA:一个Java自动化单元测试工具[J].计算机研究与发展,2010(10):1840-1848.

[5] 张巍,尹海波,孙立财.软件的单元测试方法[J].光电技术应用,2006,21(2):36-38.

作者简介:

杨 鹏(1978-),女,硕士,讲师.研究领域:数据挖掘,图形图像处理,软件测试.

endprint

将Java对象名称(每个单词的头字母大写)按照数据库命名的习惯进行格式化,格式化后的数据为小写字母,并且使用下划线分割命名单词,要求对输入数据进行非法验证。

首先新建一个TestJUnit。打开项目TestJUnit的属性页→选择“Java Build Path”子选项→点选“Add Library…”按钮→在弹出的“Add Library”对话框中选择JUnit(图2),并在下一页中选择版本4.1后点击“Finish”按钮。

图2 JUnit 运行测试界面

Fig.2 JUnit run the test interface

在JUnit运行界面提示有两个测试情况未通过,当首字母大写时得到的处理结果与预期的有偏差,造成测试失败;而当测试对 null的处理结果时,则直接抛出了异常,测试错误。

JUnit将测试失败的情况分为两种:failure和error。Failure一般由单元测试使用的断言方法判断失败引起,它表示在测试点发现了问题;而error则是由代码异常引起,这是测试目的之外的发现,它可能产生于测试代码本身的错误(测试代码也是代码,同样无法保证完全没有缺陷),也可能是被测试代码中的一个隐藏的bug。显然,被测试代码中并没有对首字母大写和null这两种特殊情况进行处理,现在对源代码进行修改,添加对这两种情况的处理,代码如下:

package sample.test;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;

import java.util.Collection;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.junit.runners.Parameterized;

import org.junit.runners.Parameterized.Parameters;

import sample.code.UserAccess;

/*

* JUnit - Parameter test sample

*/

@RunWith(Parameterized.class)

public class JunitSample {

private String user;

private String pw;

private boolean expected;

@Parameters

public static Collection dataGenerater() {

return Arrays.asList(new Object[][] {

{ "user01", "123456", true },

{ "helloworld", "123456", false },

{ "david", "re*ads", false },

{ "goodone", "onegood", true } });

}

public JunitSample(String user, String pw, boolean expected) {

this.user = user;

this.pw = pw;

this.expected = expected;

}

@Test

public void testAccessCheck() {

assertEquals(expected, UserAccess.accessCheck(user, pw));

}

}

运行测试,显示的测试结果如图3所示。

图3 测试结果

Fig.3 The test results

通过以上代码可以看出,JUnit4通过使用一个标记@Parameters注释的返回类型为Collection的静态方法产生数据,测试数据通过变量传递给测试方法,从而完成多数据输入的测试。但是随着业务的需要,测试人员需要经常增加测试数据与修改现有测试数据,JUnit4提供的硬编码方式已经愈显笨重和不便,数据与代码分离显得尤为重要。

本文所述的Feed4Junit可以良好 地解决数据与代码分离的问题,Feed4JUnit是JUnit测试框架的扩展,它通过操作来自于文件以及不同的数据源的测试数据,使单元测试变得更容易编写与维护。本文通过实例展示Feed4JUnit的安装以及测试代码与数据分离的实现,本文的实例代码全部基于针对如下一个简单的用户登录检验的类。

package sample.code;

public class UserAccess {

// simple validation for user name and password

public static boolean accessCheck(String userName, String password) {

if (userName.length() <= 4 || userName.length() > 8)

return false;

if (password.length() <= 4 || password.length() > 8)

return false;

if (userName.contains("@"))

return false;

if (password.contains("*"))

return false;

return true;

}

}

在静态方法excel中,本文采用二维数组的方式来构建测试所需要的参数列表,其中每个数组中的元素的放置顺序并没有什么要求,只要和构造函数中的顺序保持一致就可以了。现在如果再增加一种测试情况,只需要在静态方法excel中添加相应的数组即可,不再需要复制粘贴出一个新的方法出来了。

随着项目的进展,项目的规模在不断地膨胀,为了保证项目的质量,有计划的执行全面的单元测试是非常有必要的。但单靠JUnit提供的测试套件很难胜任这项工作,因为项目中单元测试类的个数在不停的增加,测试套件却无法动态的识别新加入的单元测试类,需要手动修改测试套件。

4 结论(Conclusion)

本文主要介绍了Junit相关单元测试技术,分析了应用Feed4JUnit进行单元测试的方法,用户可以方便的把测试数据存放在文件或其它数据源。通过提供简单的注释,Feed4JUnit使用户能够极其方便的实施数据与代码分离的测试,极大地增强了JUnit测试框架的易用性。本文所叙述的仅仅是Feed4JUnit提供的测试增强功能的一部分,Junit4同时还提供了大量数据的随机测试和等价类测试等众多功能。

参考文献(References)

[1] 高共革,杨静.基于.NET的单元测试自动化方法研究[J].微计算机信息,2008,24(19):280-281.

[2] 吴高峡,王芙蓉.单元测试的自动化实践[J].计算机与数字工程,2007,35(1):174-176.

[3] 吴继娟,孙媛媛,刘桂艳.基于BIST的FPGA逻辑单元测试方法[J].哈尔滨工业大学学报,2004,36(8):1074-1076.

[4] 严俊,等.JUTA:一个Java自动化单元测试工具[J].计算机研究与发展,2010(10):1840-1848.

[5] 张巍,尹海波,孙立财.软件的单元测试方法[J].光电技术应用,2006,21(2):36-38.

作者简介:

杨 鹏(1978-),女,硕士,讲师.研究领域:数据挖掘,图形图像处理,软件测试.

endprint

将Java对象名称(每个单词的头字母大写)按照数据库命名的习惯进行格式化,格式化后的数据为小写字母,并且使用下划线分割命名单词,要求对输入数据进行非法验证。

首先新建一个TestJUnit。打开项目TestJUnit的属性页→选择“Java Build Path”子选项→点选“Add Library…”按钮→在弹出的“Add Library”对话框中选择JUnit(图2),并在下一页中选择版本4.1后点击“Finish”按钮。

图2 JUnit 运行测试界面

Fig.2 JUnit run the test interface

在JUnit运行界面提示有两个测试情况未通过,当首字母大写时得到的处理结果与预期的有偏差,造成测试失败;而当测试对 null的处理结果时,则直接抛出了异常,测试错误。

JUnit将测试失败的情况分为两种:failure和error。Failure一般由单元测试使用的断言方法判断失败引起,它表示在测试点发现了问题;而error则是由代码异常引起,这是测试目的之外的发现,它可能产生于测试代码本身的错误(测试代码也是代码,同样无法保证完全没有缺陷),也可能是被测试代码中的一个隐藏的bug。显然,被测试代码中并没有对首字母大写和null这两种特殊情况进行处理,现在对源代码进行修改,添加对这两种情况的处理,代码如下:

package sample.test;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;

import java.util.Collection;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.junit.runners.Parameterized;

import org.junit.runners.Parameterized.Parameters;

import sample.code.UserAccess;

/*

* JUnit - Parameter test sample

*/

@RunWith(Parameterized.class)

public class JunitSample {

private String user;

private String pw;

private boolean expected;

@Parameters

public static Collection dataGenerater() {

return Arrays.asList(new Object[][] {

{ "user01", "123456", true },

{ "helloworld", "123456", false },

{ "david", "re*ads", false },

{ "goodone", "onegood", true } });

}

public JunitSample(String user, String pw, boolean expected) {

this.user = user;

this.pw = pw;

this.expected = expected;

}

@Test

public void testAccessCheck() {

assertEquals(expected, UserAccess.accessCheck(user, pw));

}

}

运行测试,显示的测试结果如图3所示。

图3 测试结果

Fig.3 The test results

通过以上代码可以看出,JUnit4通过使用一个标记@Parameters注释的返回类型为Collection的静态方法产生数据,测试数据通过变量传递给测试方法,从而完成多数据输入的测试。但是随着业务的需要,测试人员需要经常增加测试数据与修改现有测试数据,JUnit4提供的硬编码方式已经愈显笨重和不便,数据与代码分离显得尤为重要。

本文所述的Feed4Junit可以良好 地解决数据与代码分离的问题,Feed4JUnit是JUnit测试框架的扩展,它通过操作来自于文件以及不同的数据源的测试数据,使单元测试变得更容易编写与维护。本文通过实例展示Feed4JUnit的安装以及测试代码与数据分离的实现,本文的实例代码全部基于针对如下一个简单的用户登录检验的类。

package sample.code;

public class UserAccess {

// simple validation for user name and password

public static boolean accessCheck(String userName, String password) {

if (userName.length() <= 4 || userName.length() > 8)

return false;

if (password.length() <= 4 || password.length() > 8)

return false;

if (userName.contains("@"))

return false;

if (password.contains("*"))

return false;

return true;

}

}

在静态方法excel中,本文采用二维数组的方式来构建测试所需要的参数列表,其中每个数组中的元素的放置顺序并没有什么要求,只要和构造函数中的顺序保持一致就可以了。现在如果再增加一种测试情况,只需要在静态方法excel中添加相应的数组即可,不再需要复制粘贴出一个新的方法出来了。

随着项目的进展,项目的规模在不断地膨胀,为了保证项目的质量,有计划的执行全面的单元测试是非常有必要的。但单靠JUnit提供的测试套件很难胜任这项工作,因为项目中单元测试类的个数在不停的增加,测试套件却无法动态的识别新加入的单元测试类,需要手动修改测试套件。

4 结论(Conclusion)

本文主要介绍了Junit相关单元测试技术,分析了应用Feed4JUnit进行单元测试的方法,用户可以方便的把测试数据存放在文件或其它数据源。通过提供简单的注释,Feed4JUnit使用户能够极其方便的实施数据与代码分离的测试,极大地增强了JUnit测试框架的易用性。本文所叙述的仅仅是Feed4JUnit提供的测试增强功能的一部分,Junit4同时还提供了大量数据的随机测试和等价类测试等众多功能。

参考文献(References)

[1] 高共革,杨静.基于.NET的单元测试自动化方法研究[J].微计算机信息,2008,24(19):280-281.

[2] 吴高峡,王芙蓉.单元测试的自动化实践[J].计算机与数字工程,2007,35(1):174-176.

[3] 吴继娟,孙媛媛,刘桂艳.基于BIST的FPGA逻辑单元测试方法[J].哈尔滨工业大学学报,2004,36(8):1074-1076.

[4] 严俊,等.JUTA:一个Java自动化单元测试工具[J].计算机研究与发展,2010(10):1840-1848.

[5] 张巍,尹海波,孙立财.软件的单元测试方法[J].光电技术应用,2006,21(2):36-38.

作者简介:

杨 鹏(1978-),女,硕士,讲师.研究领域:数据挖掘,图形图像处理,软件测试.

endprint

猜你喜欢
单元测试测试数据套件
基于维修费用的关键部套件分析
“龙吟套件”创作感悟
测试数据管理系统设计与实现
基于自适应粒子群优化算法的测试数据扩增方法
工业照明超频三天棚灯套件改造工程
空间co-location挖掘模式在学生体能测试数据中的应用
一年级上册第五单元测试
一年级上册一、二单元测试
CSRmesh开发套件加速物联网产品开发
影响《标准》测试数据真实性的因素及破解策略