最近在研究JUnit4,大部分基础技术都是通过百度和JUnit的官方wiki学习的,目前最新的发布版本是4.11,结合代码实践,发现官方wiki的内容或多或少没有更新,Theory理论机制章节情况尤为严重,不知道这章wiki对应的是第几版,笔主在4.11版本中是完全跑不通的,因为接口结构已经改变了,而百度出来的博客文档更是只有Theory的基础部分,更具实际应用价值的扩展部分完全不见踪影,本文根据笔主实际编码总结经验,详细讲述如何使用4.11版JUnit的Theory理论机制。

ps. 最近发现网上有一小撮别有用心的国人转载笔主文章时,顺手丢羊把笔主文章头部标注的原文地址恶意马赛克掉,也没有在文后贴出转载地址,为了普及技术笔主就不追究了,这次故意在贴在这里,本文地址:JUnit4.11 理论机制 @Theory 完整解读

笔主下面所使用代码,仅依赖于 junit-4.11.jar,建议同时导入 hamcrest-core-1.3.jar、hamcrest-library-1.3.jar 以提供完整的assertThat支持

简单介绍Theory

使用注解@Theory取代@Test标记测试方法,可以支持带形参的测试方法签名,并使用指定的数据集自动代入进行连续多次测试,虽然暂未看到官方或其他个人的文字表述,但笔主觉得这个机制是参数化测试 Parameterized tests 的优化扩展版(Parameterized tests需要独占一个测试类,兼容性灵活性都太差了)。

使用@Theory测试方法需要在测试类头部声明@RunWith(Theories.class)

传统Theory

Theory的基础部分,通过显式预定义各种Class类型变量,在@Theory的带参测试方法中自动逐次传入相同Class类型的变量值,运行多次测试(依据预定义变量数量而定),复数形参情况使用预定义变量排列组合出实参对进行代入测试。

1、使用@DataPoint标记待用实参数据

1 @DataPoint
2 public static String **1 = “####”;
3 @DataPoint
4 public static String **2 = “####”;
5 @DataPoint
6 public static String **3 = “####”;

2.1、使用@Theory标记单形参测试方法

1 @Theory
2 // 仅输入与形参相同类型(String)的预定义@DataPoint数据,此处会自动轮流代入上面的 **1 - **3 作为实参测试数据,运行3次test1测试
3 public void test1(String ***) {
4         // 使用assume设置过滤
5         assumeThat(***);
6         assertThat(***);
7 }

2.2、复数形参测试方法

1 @Theory
2 // 使用排列组合与形参同类型(String)@DataPoint自动化输入,与命名、顺序无关,此处s1、s2将轮流使用 **1 - **3 的排列组合,如s1=**1,s2=**2或s1=**2,s2=**1,运行次数依据排列组合方案数量而定
3 public void test2(String s1, String s2) {
4         assumeThat(***);
5         assertThat(***);
6 }

Theory扩展(Popper project)

这是本文的核心部分,传统Theory指定实参变量的方式存在非常明显的局限性,无法精确控制每个形参的可用变量值范围,因此JUnit引入Popper 项目的技术,提供一种完全自定义指定实参数据集的方法。

定制@Theory测试方法实参变量值范围,主要使用 Parameter Supplier 结构

系统自带默认实现

JUnit中自带一个默认的 Parameter Supplier 实现:@TestedOn(ints = int[])

使用方式示例:

1 @Theory
2 public final void test(@TestedOn(ints = { 0, 1, 2 }) int i) {
3     assertTrue(i >= 0);
4 }

在这个例子中,可以很直观的看到形参 i 在实际运行测试中,会依次自动代入取值为 ints 指定的数组{0, 1, 2}中每个元素

完全自定义实现

JUnit默认只提供了一个int型的简单 Parameter Supplier 实现,而Theory机制真正的价值在于,能参考@TestedOn的做法,相对简单的完全自定义出可重用 Parameter Supplier,适应于各种复杂要求的限定范围参数值测试场景,满足开发者所需的高度动态自定义范围取值自动化测试,同时保留与一般@Test相同的强大兼容性,作为本文核心中的战斗机,下面将通过两个栗子,详细描述如何一步步实现自定义 Parameter Supplier。

自定义实现I(动态实参值表)

本方式以一个自定义注解接口@Between为例,展示如何通过读取注解属性变量值,动态创建相应的实参数据集。

1、定义annotation注解接口 Between:

1 @Retention(RetentionPolicy.RUNTIME)
2 // 声明注解接口所使用的委托处理类
3 @ParametersSuppliedBy(BetweenSupplier.class)
4 public @interface Between{
5     // 声明所有可用参数,效果为 @Between([first = int,] last = int)
6     int first() default 0;  // 声明默认值,成为非必须提供项
7     int last();
8 }

2、定义委托处理类 BetweenSupplier:

 1 public class BetweenSupplier extends ParameterSupplier{
 2
 3     @Override
 4     public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
 5
 6         // 自定义实参值列表
 7         List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
 8
 9         // 获取注解变量
10         Between between = sig.getAnnotation(Between.class);
11
12         // 获取通过注解@Between传入的first值
13         int first = between.first();
14
15         // 获取通过注解@Between传入的last值
16         int last = between.last();
17
18         for (int i = first; i <= last; i++){
19           // PotentialAssignment.forValue(String name, Object value)
20           // name为value的描述标记,没实际作用
21           // value为实参可选值
22             list.add(PotentialAssignment.forValue("name", i));
23         }
24         return list;
25     }
26 }

3、调用方式:

1 @Theory
2 public final void test(@Between(last = 0) int i, @Between(first = 3, last= 10) int j) {
3     // i 取值为 0(first默认=0,last=0),j 取值为 3-10
4     assertTrue(i + j >= 0);
5 }

自定义实现II(静态实参值表):

本方式以一个自定义注解接口@AllValue为例,展示如何静态地内部创建固定的实参数据集。

1、定义annotation注解接口 AllValue(按“使用II”方式调用可省略此步骤):

1 @Retention(RetentionPolicy.RUNTIME)
2 // 声明注解接口所使用的委托处理类
3 @ParametersSuppliedBy(AllValueSupplier.class)
4 // 空接口,不需要接受任何参数变量
5 public @interface AllValue{ }  

2、定义委托处理类 AllValueSupplier:

 1 public class AllValueSupplier extends ParameterSupplier{
 2
 3     @Override
 4     public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
 5
 6         List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
 7   
 8       // 内定提供固定的可用实参值表
 9         for (int i = 0; i <= 100; i++){
10             list.add(PotentialAssignment.forValue("name", i));
11         }
12         return list;
13     }
14 }

3.1、使用I(使用自定义注解):

1 @Theory
2 public final void test(@AllValue int i) {
3     // i 取值为 0-100
4     assertTrue(i >= 0);
5 }

3.2、使用II(可省略第1步注解接口AllValue的定义):

1 @Theory
2 public final void test(@ParametersSuppliedBy(AllValueSupplier.class) int i) {
3     // i 取值为 0-100
4     assertTrue(i >= 0);
5 }

JUnit官方wiki及下载地址:https://github.com/junit-team/junit/wiki

Theory理论机制英文原文wiki(注:已过期,不适用于4.11):https://github.com/junit-team/junit/wiki/Theories

转载于:https://www.cnblogs.com/wavky/p/JUnit4_Theory.html

JUnit4.11 理论机制 @Theory 完整解读相关推荐

  1. java 下载junit的jar包_junit4下载-Junit4.11完整包【附使用方法】-东坡下载

    JUnit测试框架将测试更加便捷和容易,编写测试代码也是简单.明了,功能强大. Junit4.11jar包源码文档 包含hamcrest-core-1.3.jar junit-4.7.jar juni ...

  2. Java 11 正式发布,新特性解读

    Java 11 正式发布,新特性解读 杨晓峰   2018 年 9 月 26 日 话题:Java语言 & 开发 不知不觉 JDK 11 已经发布了,从 9 开始,JDK 进入了让人学不动的更新 ...

  3. UUP, Windows 11 更新机制的未来

    UUP, Windows 11 更新机制的未来 时间线 适用更新类型版本 UUP 带来的功能改进 对部署带来的几点影响 文件格式变化对部署的影响 对于通过第三方从MS Server获取KB方案的影响 ...

  4. 机器学习基石06:泛化理论(Theory of Generalization)

    本文介绍了机器学习的泛化理论,包括突破点的限制,上限函数的基本情形,上限函数的归纳情形以及形象化的证明. 系列文章 机器学习基石01:机器学习简介 机器学习基石02:感知器算法(Perceptron ...

  5. Spark知识体系完整解读

    Spark知识体系完整解读(内有福利) 作者:杨思义,2014年6月至今工作于北京亚信智慧数据科技有限公司 BDX大数据事业部,从2014年9月开始从事项目spark相关应用开发. 来源:数盟 Spa ...

  6. 使用JUnit-4.11报java.lang.NoClassDefFoundError:

    2019独角兽企业重金招聘Python工程师标准>>> 最好的解决方法是: (1)换成junit-4.8.jar或是junit-4.11.jar (2)junit-4.11.jar ...

  7. 城乡收入不平等及其动态演化模型构建——中国城乡收入差距变化的理论机制

    摘要:借鉴贝克尔的"家庭收入不平等及世代之间的变动性"理论,从要素投入的角度,将物质资本.人力资本和政府投入作为基本变量来分析我国城乡收入差距产生及其动态演变的理论机制.主要结论: ...

  8. 注意力机制最新综述解读(last revised 12 Jul 2021)

    注意力机制最新综述解读(last revised 12 Jul 2021) 论文连接 [参考翻译]沈子恒的博客-CSDN博客_注意力机制 1.介绍   注意力模型(AM)最早应用于机器翻译[1],现在 ...

  9. linux信号嵌套,LINUX0.11信号机制

    原标题:LINUX0.11信号机制 一.信号的本质 信号(signal)是Linux操作系统在软件层面上对中断的模拟,是一种异步通信机制.进程之间可以相互发送信号来通知对方发生了什么事情,一个进程不必 ...

最新文章

  1. springboot2.4跨域配置的方法
  2. 漫画:你真的懂Github吗?
  3. 更快更强,谷歌提出SWideRNet:全景分割新标杆来啦!
  4. ubuntu下shutter的用法
  5. php代码以什么开始以什么结束,【后端开发】php语句以什么符号结束
  6. ux和ui_他们说,以UX / UI设计师的身份加入一家初创公司。 他们说,这会很有趣。
  7. 关于银联在线支付和短彩信接口的开发——总结
  8. 深入理解InnoDB(4)—索引使用
  9. 《啊哈,C语言》 第一章课后习题练习记录
  10. 计算机视觉 图像算法工程师 面试问题总结
  11. 如何通过Python暴力破解网站登陆密码
  12. Cartographer实时显示三维点云地图
  13. 关于实时推送系统的那点事
  14. html a标签属性 rel=‘nofollow‘
  15. OpenStack Cinder特性之Volume-backed image介绍与验证
  16. 获取“今日头条”西瓜视频
  17. 计算机平面设计评分标准,竞赛各专业评分标准.DOC
  18. 微信公众平台模拟登陆和发送消息详解
  19. execjs 模块 call() 方法报错 AttributeError: ‘NoneType‘ object has no attribute ‘replace‘
  20. C语言实现三子棋(五子棋可以改赢得函数即可)

热门文章

  1. MySql库中所有表的属性_SQL查询某库所有的表所有的字段及字段的属性
  2. centos7 网卡配置vlan_【linux】Centos7单网卡多VLAN配置
  3. python打印列表元素_python打印列表中指定元素的所有下标
  4. python pandas_Python库Pandas数据可视化实战案例
  5. python如何创建不同元素的矩阵_python – 如何在数据帧中创建矩阵元素的数...
  6. android 事件冒泡,Android事件分发
  7. 【工具软件】webstorm如何使用快捷键生成固定代码
  8. 【java】兴唐课程第五节到第九节知识点总结
  9. ios NSLayoutConstraint
  10. arial unicode ms字体_5个检测商用字体和免费字体合集的网站