转载-使用 Feed4JUnit 进行数据与代码分离的 Java 单元测试

 

JUnit 是被广泛应用的 Java 单元测试框架,但是它没有很好的提供参数化测试的支持,很多测试人员不得不把测试数据写在程序里或者通过其它方法实现数据与代码的分离,在后续的修改和维护上有诸多限制和不便。Feed4JUnit 是开源的基于 JUnit 的扩展,通过使用 Feed4JUnit 提供的注释,用户可以很方便的把测试数据存放在文件或其它数据源。本文通过介绍及简单示例,使读者了解并能够使用 Feed4JUnit, 方便的实现数据与代码分离的测试。

Feed4JUnit 与 JUnit

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

基于以上场景,JUnit 4 提供了参数化的特性,从而能够实现不同数据输入对相同测试代码的测试,如清单 1 所示:

清单 1. JUnit 4 参数化测试代码示例
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;@Parameterspublic 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;}@Testpublic void testAccessCheck() {assertEquals(expected, UserAccess.accessCheck(user, pw));}
}

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

幸好,本文所述的 Feed4JUnit 良好的解决了数据与代码分离的问题,Feed4JUnit 是 JUnit 测试框架的扩展,它通过操作来自于文件以及不同的数据源的测试数据,使您的单元测试变得更容易编写与维护。

本文将通过示例向您展示 Feed4JUnit 的安装以及测试代码与数据分离的实现,请注意本文的示例代码全部基于针对如下一个十分简单用户登录检验的类,并且假定您正在使用 Eclipse 作为您的 IDE,请看清单 2 类代码:

清单 2. 实例类
package sample.code;public class UserAccess {// simple validation for user name and passwordpublic 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;}
}

Feed4JUnit 的下载及安装

1. Feed4JUnit 是开源的测试组件,您可以从如下链接下载最新版本:

http://sourceforge.net/projects/feed4junit/files/

2. 解压下载的 zip 包,复制整个 lib 文件夹到您的 Java 项目的根目录,如图 1:

图 1. 复制 lib 到项目根目录
图 1. 复制 lib 到项目根目录

3. 选定项目,右键选择项目的属性,然后通过 Add JARs 将步骤 2 中 lib 文件夹下的所有 Jar 添加到项目的 Build Path 下,如图 2

图 2. 添加 Jar 到 Build Path
图 2. 添加 Jar 到 Build Path

通过以上三步,您已经准备好您的 Feed4JUnit 环境并可以开始使用它,当然,开发测试代码之前,您必需要将 Feed4JUnit 相应的包 Import 进您的类。

使用 Feed4JUnit 实现数据与代码分离的测试

Feed4JUnit 的数据源可以包括以下几种类型 - 文件 (CSV 或者 Excel )、数据库、自定义数据源。

Feed4JUnit 使用一个特殊的运行类 Feeder.class,用来支持与标识参数化测试,如果您想要编写数据与代码分离的测试脚本,必须在您的测试类上增加注释 @RunWith(Feeder.class) 。同时,您需要使用 @Test 来标示您实现测试的方法,并且使用 @Source 来声明和接收数据源的数据,基本的代码结构如清单 3 所示:

清单 3. 基本代码结构
package sample.test;import static org.junit.Assert.assertEquals;
import org.databene.feed4junit.Feeder;
import org.databene.benerator.anno.Source;
import org.junit.Test;
import org.junit.runner.RunWith;/** Feed4JUnit - @RunWith, @Test and @Source*/
@RunWith(Feeder.class) //Specify the class will be ran as Feeder class
public class Feed4JSample {@Test //Specify the method as a test method@Source()//Specify the input data sourcepublic void testAccessCheck() {assertEquals(true, true);}
}

以文件作为数据源

Feed4JUnit 支持从 CSV 或者 Excel 文件里面读取数据作为输入,这里我们以 Excel 文件为例。

1. 在测试项目的根目录下创建 Data.xls 数据文件,样例数据如图 3,默认情况下,第一行会以列名存在,在运行过程中不会作为数据读取。

图 3. Excel 数据源
图 3. Excel 数据源

2. 创建测试类并在接收数据的测试方法上声明数据源为 @Source("Data.xls"),Excel 中的数据在传递过程中会自动按照列与测试方法的参数的位置顺序进行匹配,并以行作为一个单位读取并传递给测试方法体。比如图 3 中的 user 列的值会做为方法的第一个参数传入方法体中,pw 列的值会作为方法的第二个参数,以此类推。在测试进行过程中,首先在 Excel 文件中读取一行(包含三列),接着按照位置顺序将数据传递到方法体中(每列按顺序对应一个参数)进行执行,执行完成后读取 Excel 中的下一行进行相同流程的测试,其原理与 Java 中的迭代器十分类似。请注意当数据文件中数据的列数小于测试方法参数的个数的时候,测试会因为位置不匹配而失败。

清单 4 包括从 CSV 和 Excel 读取和传递数据的示例:

清单 4. 文件数据源示例
package sample.test;import static org.junit.Assert.assertEquals;import org.databene.benerator.anno.Source;
import org.databene.feed4junit.Feeder;
import org.junit.Test;
import org.junit.runner.RunWith;import sample.code.UserAccess;/** Feed4JUnit - Get Data from CSV/Excel File source*/@RunWith(Feeder.class)
public class F4JfromFile {@Test@Source("Data.csv")//CSV sourcepublic void testAccessCheck_CSV(String userName, String pw, boolean expected) {assertEquals(expected, UserAccess.accessCheck(userName, pw));}@Test@Source("Data.xls")//Excel sourcepublic void testAccessCheck_Excel(String userName, String pw, boolean expected) {assertEquals(expected, UserAccess.accessCheck(userName, pw));}
}

3. 运行测试,因为 Feed4Junit 是 JUnit 的扩展,所以运行方式与 JUnit 完全相同,即以 JUnit 运行即可,运行结果如图 4 所示,我们可以看到,Data.xls 中的数据已全部传入测试方法并运行。

图 4. 运行结果示例
图 4. 运行结果示例

以数据库作为数据源

通过使用 @Database ,您可以很方便的使用来自于数据库的数据,这在进行大量测试数据测试的时候或者复用现有的应用业务数据作为测试数据的情况下比较有用。

当您使用来自数据库的数据源的时候,首先必须使用 @Database 声明数据库的信息 ,可以为类或方法添加 @Database 注释 , 如果注释类为 @Database 的时候,类中所有的方法都可以使用此数据库的数据作为源,当声明 @Database 于方法的时候,此类中仅此方法可以调用数据库作为数据源。@ Database 具有一些属性,用于声明用于连接数据库信息,请看一下说明:

id: 一个用于标识数据库数据源标识符,在测试方法的 @Source 中进行引用关联

url:数据库的 URL

driver: 数据库的驱动

user: 数据库的用户名

password:数据库的密码

完成以上数据库的定义后,需要在测试方法的 @Source 中引用您所需要的库,使用属性 id 和 selector 可以完成此操作:

id: @Source 中的 id 和 @Database 的 id 相对应关联

selector:SQL 语句,用于查询出相应的数据传递给测试方法

以下我们以 DB2 作为数据源,使用 DB2 的 Sample 数据库,并创建名为 TEST 的表来存储测试数据,测试数据与图 3 Excel 数据源的完全相同,请看图 5。

图 5. 数据表中的测试数据
图 5. 数据表中的测试数据

首先,创建测试类,添加 @Database 注释并增加数据库的连接信息,同时指定一个表示数据库的 id,在测试方法的 @Source 中通过 id 进行关联,并制定 selector 的语句进行数据查询,例如本例中的 selector = "select * from TEST",会从 TEST 表中取出全部数据用于测试,细节请参考以下代码示例:

清单 5 为在类上声明 @Database。

清单 5. 在类上声明 @Database
package sample.test;import static org.junit.Assert.assertEquals;import org.databene.benerator.anno.Database;
import org.databene.benerator.anno.Source;
import org.databene.feed4junit.Feeder;
import org.junit.Test;
import org.junit.runner.RunWith;import sample.code.UserAccess;/** Feed4JUnit - Get Data from Database, all test methods can use the database data*/
@RunWith(Feeder.class)
@Database(id = "testdb", url = "jdbc:db2://localhost:50000/SAMPLE", driver = "com.ibm.db2.jcc.DB2Driver", user = "db2admin", password = "db2admin")
public class F4JfromDB {@Test@Source(id = "testdb", selector = "select * from TEST")public void testAccessCheck(String userName, String pw, String expected) {Boolean bSucess = UserAccess.accessCheck(userName.trim(), pw.trim());assertEquals(expected.trim(), bSucess.toString());}
}

清单 6 为在方法上声明 @Database:

清单 6. 在方法上声明 @Database
/** Feed4JUnit - Get Data from Database, only the specified method can use the database data*/@RunWith(Feeder.class)
public class F4JfromDB_Method {@Test@Database(id = "testdb", url = "jdbc:db2://localhost:50000/SAMPLE", driver = "com.ibm.db2.jcc.DB2Driver", user = "db2admin", password = "db2admin")@Source(id = "testdb", selector = "select * from TEST")public void testAccessCheck(String userName, String pw, String expected) {Boolean bSucess = UserAccess.accessCheck(userName.trim(), pw.trim());assertEquals(expected.trim(), bSucess.toString());}
}

测试运行过程中,通过 url,driver 等信息建立数据连接,通过 selector 发出数据请求,最后完成查询并把数据传递给测试方法,数据在传递给方法的时候,会按数据表的列的顺序与参数进行匹配,运行结果与图 4 类似。

自定义数据源

除了 CSV,Excel 和数据库的数据源外,Feed4JUnit 还提供自定义数据源,以满足不同用户的需求,用户同样可以通过封装 JUnit 4 提供的参数化测试的方法来完成数据源自定义,所有这里作者不再详述,用户可以封装并取得不同的数据源的数据,传递给 Feed4JUnit 的相应接口,来完成数据源的自定义。

结束语

本文通过对比介绍和简单易懂的实例全面讲解了 Feed4JUnit 对数据与代码分离的测试支持。通过提供简单的注释,Feed4JUnit 使用户能够极其方便的实施数据与代码分离的测试,极大地增强了 JUnit 测试框架的易用性。 相信您已经在本文的叙述中看到它的优点。同时,本文所叙述的仅仅是 Feed4JUnit 提供的测试增强功能的一部分,Feed4JUnit 同时还提供了大量数据的随机测试和等价类测试等众多功能,如果您感兴趣可以自行参考。

转载于:https://www.cnblogs.com/testermark/p/4075365.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

青岛智能院助力智慧城市 打造智能产业“黄埔军校”

作为青岛市的主干道之一&#xff0c;山东路的拥堵状况一直让人头疼。近日&#xff0c;因为一种交通组织优化方案的实施&#xff0c;山东路和延吉路的通行率提高了近50%。而研发这种智能管控系统的正是位于青岛高新区的青岛智能产业技术研究院。截止今年5月份&#xff0c;青岛智…

oracle备份归档文件,oracle 如何不备份已经备份的归档

在Oracle数据库备份归档日志时&#xff0c;通常会保存最近几天的归档日志文件不删除。如&#xff1a;backup archivelog all;delete noprompt archivelog all completed before sysdate -14; 在本地保留14天的归档日志&#xff0e;再备份时&#xff0c;归档会重复再备份一次。…

博客迁移指南

1.今天起 博客迁移至farbox 2. 新博客地址&#xff0c;http://yoon.farbox.com转载于:https://www.cnblogs.com/yoon/p/5003384.html

iOS 第三方登录 !

http://www.it165.net/pro/html/201409/21854.html 转载于:https://www.cnblogs.com/Seeulater/p/4076727.html

dp递推 hdu1978

How many ways Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5422 Accepted Submission(s): 3185 Problem Description这是一个简单的生存游戏&#xff0c;你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的…

codeforce-600C. Make Palindrome(贪心)

http://codeforces.com/problemset/problem/600/C&#xff1b; 题意&#xff1a;给你一个小写字母组成的英文串&#xff0c;将它转换为回文串&#xff0c;要求&#xff0c;改变的字母的个数最小&#xff0c;移动字母不算改变字母。 所得的串字典序是最小的。最后输出所得到的串…

oracle触发器没有效果,触发器不起作用,各位帮忙看看什么原因?

测试数据模型如下&#xff1a;Create Table test_c (Id Number,seq Number,state varchar2(5));select a.*,rowid from test_c aInsert Into test_cValues(1011,101,00A);Insert Into test_cValues(1012,101,00A);Insert Into test_cValues(1021,102,00A);Insert Into test_cVa…

10个我最喜欢问程序员的面试问题

最近我拜读很多文章&#xff0c;都是介绍面试问题的&#xff0c;我真心不理解&#xff0c;面试官代表公司想要聘用的是最优秀的程序员&#xff0c;那就意味着需要想出一些有意义的面试问题。如果你就提一些毫无用处的垃圾问题&#xff0c;那么很容易遗漏很多能干的程序员。当然…

oracle动态性能视图和静态,oracle最重要的9个动态性能视图

v$session v$session_wait (在10g里功能被整合,凑合算1个吧.)v$processv$sqlv$sqltextv$bh (更宁愿是x$bh)v$lockv$latch_childrenv$sysstatv$system_event按组分的几组重要的性能视图1。System 的 over viewv$sysstat , v$system_event , v$parameter2。某个session 的当前情况…

glTF格式初步了解

glTF格式初步了解近期看到Qt 3D的进展。偶然了解到了一种新的格式&#xff1a;glTF格式。这样的格式据说比现有的3D格式更加符合OpenGL应用的须要。这引起了我的好奇。于是我在Qt 3D的外部链接中找到了有关glTF的相关链接。上海萌梦信息科技有限公司&#xff08;微博&#xff1…

【】局部刷新:

【】局部刷新&#xff1a; //页面加载时绑定按钮点击事件$(function(){ $("#按钮id").click(function(){ refresh(); });});//点击按钮调用的方法function refresh(){ window.location.reload();//刷新当前页面. //或者下方刷新方法 //par…

技术贴-搜狗打字

超强技术帖&#xff1a;遇到不会读的字&#xff0c;怎么用拼音打出来&#xff1f;】方法很简单&#xff0c;就是先打个“u”然后打各个部首的读音&#xff0c;就能在拼音输入法中打出来哦。比如&#xff0c;骉&#xff0c;可以输入umamama&#xff0c;输入法就会自动出现“骉”…

【第二十七章】 springboot + zipkin(brave-okhttp实现)

本文截取自&#xff1a;http://blog.csdn.net/liaokailin/article/details/52077620 一、前提 1、zipkin基本知识&#xff1a;附8 zipkin 2、启动zipkin server&#xff1a; 2.1、在官网下载服务jar&#xff0c;http://zipkin.io/pages/quickstart.html&#xff0c;之后使用命令…

Oracle 数据定义语言,oracle 数据定义语言(DDL)语法

DDL语言包括数据库对象的创建(create)、删除(drop)和修改(alter)的操作1.创建表语法create table table_name(column_name datatype [null | not null],column_name datatype [null | not null],..........[constraint])constraint 是为表中的列设置约束&#xff0c;常见的有…

Android内存泄漏问题(一)

前言 不少人认为JAVA程序&#xff0c;因为有垃圾回收机制&#xff0c;应该没有内存泄露。 其实如果我们一个程序中&#xff0c;已经不再使用某个对象&#xff0c;但是因为仍然有引用指向它&#xff0c;垃圾回收器就无法回收它&#xff0c;当然该对象占用的内存就无法被使用&…

向上弹出菜单jQuery插件

插件名&#xff1a;柯乐义英文名&#xff1a;Keleyijs文件名称&#xff1a;jquery.keleyi.js插件功能&#xff1a;该插件可以让你轻易地在页面上构建一个向上弹出的二级菜单。支持浏览器&#xff1a;keleyi 0.1.4版本支持IE6以及以上、Chrome、火狐(Firefox)、欧朋(Opera)、Saf…

oracle在线sql数据库设计,一款在线ER模型设计工具,支持MySQL、SQLServer、Oracle、Postgresql...

在线QQ客服&#xff1a;1922638专业的SQL Server、MySQL数据库同步软件介绍一个在线ER模型生成工具&#xff0c;该工具可以在线为多个数据库的DDL文件生成ER模型图&#xff0c;并支持MySQL&#xff0c;SQLServer&#xff0c;Oracle&#xff0c;PostgreSQL和其他数据库。主要功能…

_M_invoke(_Index_tuple_Indices...)

2019独角兽企业重金招聘Python工程师标准>>> [hadoopiZ25s7cmfyrZ C_script]$ cat test_thread_a.cpp #include <iostream> #include <atomic> #include <thread> #include <vector>std::atomic<int> global_counter(0);void increa…

十年后2023年再读这篇文章,看看我将会怎么样?

http://blog.csdn.net/wojiushiwo987/article/details/8453881看到一篇文章不错【清华差生10年奋斗经历】 &#xff0c;写给将要工作的自己&#xff0c;十年后2023年再读这篇文章&#xff0c;看看我将会怎么样&#xff1f; 在2012年收关时刻&#xff0c;看到如此激励的文章&…

1203正规式转换为有穷自动机

1 #include<stdio.h>2 #include <ctype.h>3 #define ok 14 #define error 05 #define MAXREGLUARLONG 406 #define MAXSTATELONG 40 7 #define MAXCAHRSLONG 40 8 typedef int state;9 int iCurrentState0; //初态以1开始10 int iPreState0;11 in…