Hamcrest Matchers的高级创建

介绍

上一次 ,我讨论了Hamcrest Matcher是什么,如何使用以及如何制作。 在本文中,我将解释创建Hamcrest Matchers的更多高级步骤。 首先,我将分享如何使您的匹配器更易于类型安全,然后介绍无状态匹配器的一些技术,最后是如何减少测试类上的大量静态导入。 我还将给您一些有关命名静态工厂方法的快速提示。

类型安全匹配器

您可能已经在上次开发的matchs()方法中注意到了,我在注释中指出,我曾使用“ yoda条件”来避免null检查和类型检查。 首先,自己对yoda条件进行一些研究不会有什么坏处(我可能有一天会发表一篇有关它的文章,但不能保证),但是这里要注意的最大事情是某种类型检查和需要空检查。 这是因为matchs()方法接受一个对象,而不是Generics参数中指定的类型。

如Hamcrest的文档中所述:

此方法与Object匹配,而不是与通用类型T匹配。这是因为Matcher的调用者在运行时不知道类型是什么(由于Java通用类型已擦除类型)。

因此,我们需要确定要传入的对象的类型。此外,我们还应确保没有传入任何空值(除非我们的特定Matcher可以这样做,但这非常罕见),或者在至少要确保传入的null不会导致NullPointerException。

但是有一种更简单的方法:TypeSafeMatcher。 如果扩展此类而不是BaseMatcher类,它将为您执行类型检查和null检查,然后将对象传递给仅采用泛型指定类型的匹配方法。

定义TypeSafeMatcher非常类似于我们上次定义Matcher的方式,但有一些区别:除了覆盖matchs()之外,您还可以替代使用通用类型而不是Object的matchesSafely()。 而不是覆盖describeMismatch(),而是覆盖describeMismatchSafely()。 可能没有一个新的describeTo()可能令人惊讶,但是看到它除了Description之外没有其他内容,因此不需要类型安全的版本。

否则,创建TypeSafeMatcher几乎是相同的。

不过,我不得不提我上周忘记的事情。 定义自己的Matchers的人不需要重写describeMismatch()或describeMismatchSafely()方法。 BaseMatcher和TypeSafeMatcher都具有这些方法的默认实现,这些方法的简单实现是简单地输出“ was item.toString() ”(如果TypeSafeMatcher获得不正确类型的项,则“ was of itemClassNameitem.toString()” )”。

这些默认实现通常足够好,但是如果使用的类型没有toString()的有用实现,则使用您自己的不匹配消息来描述该项目的问题显然更有用。 即使该类具有不错的toString()实现,我也总是这样做,因为它可以更快地解决问题。

有关其他可扩展匹配器类的说明

Hamcrest核心库中还有其他几个Matcher类,供用户从中扩展。 这些有几种口味。

首先,有CustomMatcher和CustomTypeSafeMatcher。 这些设计用于通过匿名类一次性创建Matchers。 他们可能是有用的,但我更愿意总是在情况下,正确执行我曾经确实需要它一次。

接下来,有DiagnosingMatcher和TypeSafeDiagnosingMatcher,它们使您可以在match()方法中创建不匹配描述。 这似乎是用一块石头杀死两只鸟的好方法,但是我有几块牛肉:1)它违反了SRP 2)如果存在不匹配,它再次调用matchs()方法只是为了填充在不匹配说明中。 因此,第一个调用将忽略获取描述,第二个调用将忽略匹配。

您可以扩展的最后一个特殊的Matcher是FeatureMatcher。 这可能非常有用,但理解起来很复杂(我不确定我是否理解正确–直到我尝试自己动手做一个或阅读如何做一个为止)。 如果我弄清楚并获得了很好的理解,我将在这里为您写另一篇文章。

无状态匹配器

不需要将任何内容传递到其构造函数(因此,它是静态工厂方法)的任何Matcher都是无状态Matcher。 它们与其他Matcher相比有一个很小的优势,因为您只需要在任何时候存在一个实例,就可以在需要使用该Matcher的任何时间重用它。

这是一个非常简单的补充。 您需要做的就是创建该类的静态实例,并使您的静态工厂返回该实例,而不是调用构造函数。 库附带的IsEmptyString Matcher可以完成此操作(上一次我们的示例没有,但这是为了简单起见)。

减少静态进口数量

用Hamcrest Matchers编写了相当多的测试之后,您可能会注意到文件顶部有很多静态导入。 一段时间后,这可能会成为很大的麻烦事,所以让我们看一下可以减轻此问题的方法。

实际上,这几乎与上一个解决方案一样简单。 您可以通过创建本质上为您执行此操作的新类来减少静态导入。 这个新类具有烦人的静态导入,但随后定义了自己的静态工厂方法来委托给原始对象。 这是将一些核心Matchers组合到一个地方的示例:

import org.hamcrest.core.IsEqual;
import org.hamcrest.core.IsNull;
import org.hamcrest.core.IsSame;
import org.hamcrest.Matcher;public class CoreMatchers
{public static  Matcher equalTo(T object) {return IsEqual.equalTo(object);}public static Matcher notNullValue() {return IsNull.notNullValue();}public static  Matcher notNullValue(Class type) {return IsNull.notNullValue(type);}public static Matcher nullValue() {return IsNull.nullValue();}public static  Matcher nullValue(Class type) {return IsNull.nullValue(type);}public static  Matcher sameInstance(T target) {return IsSame.sameInstance(target);}public static  Matcher theInstance(T target) {return IsSame.theInstance(target);}
}

然后,要使用任何或所有Matcher,只需静态导入CoreMatchers。*还有一种生成这些组合Matcher类的方法,如官方Hamcrest教程所示 。 我不会继续讨论它,因为它不在本文讨论范围之内,而且我也不喜欢它。

结束提示:命名

如果您阅读了官方的Hamcrest教程和/或查看了内置的Matchers,您可能会注意到静态工厂方法的命名趋势。 通用语法匹配“断言testObjectfactoryMethod ”。 方法名称的语法通常设计为可以在“ is”之前使用的当前时态动作。在命名自己的静态工厂方法时,通常应遵循此约定,但实际上我建议将“ is”放入名称中已经。 这样,Matcher的用户无需将您的方法嵌套在is()方法内。 但是,如果执行此操作,则还需要创建反函数。 允许使用is()方法包装Matcher的原因是,因此您也可以将其包装在not()方法中,以测试已经测试的内容的逆函数。 这将导致类似“断言testObject不是factoryMethod ”的句子。如果您认为遵循约定对特定Matcher的限制太大,只需确保使用当前的时态动作测试即可。 例如,我做了一个匹配器,检查是否抛出了一个异常,该异常的静态工厂方法是throwsA()。 我只是不喜欢将它命名为throwingA()以便与“ is”一起使用。 但是,如果再次违反约定,则必须确定要创建一个静态静态工厂方法。 例如,如果要实现自己的逆工厂,最简单的方法通常是用not()包装正工厂。 因此,我的nottThrowA()方法将返回not(throwsA())。 不过要小心:有时候,将正负误转实际上并不能给出您想要的正确逆。

奥托罗

好吧,这就是我为您准备的。 如果您想让我进一步了解Hamcrest Matchers,请在评论中告诉我。 否则,您可以在其github页面上的Hamcrest Matchers上进行自己的研究。下周,我将讨论如何让您的Hamcrest Matchers以类似于AssertJ断言的流畅方式检查多个事情。

翻译自: https://www.javacodegeeks.com/2015/01/advanced-creation-of-hamcrest-matchers.html

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

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

相关文章

嵌入式成长轨迹37 【Zigbee项目】【CC2430基础实验】【自动闪烁】

最为简单的代码&#xff0c;只用到一个寄存器P1DIR。因为点亮的led灯&#xff08;p1.0和p1.1&#xff09;的管脚是p1的&#xff0c;要输出就得将这两个管脚设置为输出管脚。该寄存器用0~8对应1.0~1.8管脚。 1 //main.c2 #include <ioCC2430.h>3 4 #define uint unsigned …

博客园CodingLife模板样式优化

博客园CodingLife模板样式优化&#xff0c;小屏和大屏均做了优化&#xff0c;感兴趣的园友可以复制到你的页面定制CSS代码中&#xff0c; 源码地址&#xff1a;http://www.cnblogs.com/blog/customcss/334547.css 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.com

如何允许用户自定义UI

理念 利用JavafX / FXML的声明性设计模式&#xff0c;并允许用户仅通过使用例如SceneBuilder打开某个视图即可重新定制布局或添加新控件&#xff0c;甚至根据用户需要更改样式&#xff0c;从而无需任何编码即可自定义某个视图。 FXML文件 CSS基本上可以放置在通过URL可以到达的…

WPF控件和布局

WPF控件和布局&#xff0c;根据刘铁猛《深入浅出WPF》书籍讲解内容&#xff0c;主要记录控件和布局的原理&#xff0c;如果有不足的地方&#xff0c;请大牛们键盘下留情--轻喷&#xff01;如果还算有用&#xff0c;请给点动力&#xff0c;支持一把&#xff01; 一、WPF里的控件…

css背景图片定位

背景图默认平铺&#xff1a; background-repeat: no-repeat;/*不平铺*//*repeat-x;沿X轴平铺*//*repeat-x;沿Y轴平铺*/ 背景图片定位&#xff1a; background-position: 100px 30px;/* X轴 Y轴 *//* 20% 20%; 百分比的方式 *//* left|center|right top|center|bottom */ 背景中…

使用GZIP和压缩数据

抽象 我们都知道用zip或gzip压缩文件的含义。 但是在Java中使用压缩文件并不像您想的那样简单明了&#xff0c;尤其是当您不是直接使用文件而是压缩流数据时。 我们会去&#xff1a; 如何将字符串转换为压缩/压缩字节数组&#xff0c;反之亦然 创建用于读取和写入文件的实用程…

Oracle ——概述 Oracle 5 步调优方法论

http://www.toadworld.com/KNOWLEDGE/KnowledgeXpertforOracle/tabid/648/TopicID/OPS3/Default.aspx 对 Oracle 调优应该采取积极的态度。如果等到用户开始抱怨性能&#xff0c;才调优通常以为时已晚&#xff0c;即便是最有效的调优策略。性能问题确定和处理的时间越晚&#x…

js,jq.事件代理(事件委托)复习。

<ul id "lists"><li>列表1</li><li>列表2</li><li>列表3</li><li>列表4</li><li>列表5</li><li>列表6</li></ul>js委托&#xff1a; var lists document.getElementById(&qu…

整体服务器与微服务

介绍 刚开始时&#xff0c;由于要求简单&#xff0c;所以应用程序既简单又小。 随着时间要求和需求的增长&#xff0c;我们的应用程序变得越来越大&#xff0c;越来越复杂。 这导致将单片服务器开发和部署为一个单元。 在某种程度上&#xff0c;微服务可以通过简单的应用程序回…

NEXUS S安卓4.0/4.1 【完美】 ROOT教程

原文链接&#xff1a;http://bbs.gfan.com/android-3517082-1-1.html 进行bootloader解锁&#xff08;即使解锁&#xff0c;再上锁&#xff09;&#xff0c;会清除你手机上的【所有】数据&#xff08;包括内部的16G SD 存储&#xff09;&#xff0c;包括但不限于应用、设置、联…

CSS中的各种FC

什么是FC&#xff1f; Formatting Context&#xff0c;格式化上下文&#xff0c;指页面中一个渲染区域&#xff0c;拥有一套渲染规则&#xff0c;它决定了其子元素如何定位&#xff0c;以及与其他元素的相互关系和作用。 BFC 什么是BFC Block Formatting Context&#xff0…

HDU 2647 Reward 拓扑排序

http://acm.hdu.edu.cn/showproblem.php?pid2647 题意&#xff1a; 输入N和M代表N个人和M组数据&#xff0c;M组数据中的A和B代表A的工资要比B的工资高&#xff0c;底薪是&#xff08;888元&#xff09;&#xff0c;问你这个老板至少要付 多少钱给这些员工&#xff0c;A比B工资…

EE Servlet 3:简单表单处理

对于大多数Web开发人员而言&#xff0c;Web应用程序中的表单处理就像小菜一碟。 如果我们无法捕获用户的输入并进行处理&#xff0c;将不会有太大用处。 因此&#xff0c;我在servlet3示例中包含了一个简单的FormServlet &#xff0c;该示例演示了您可能会遇到的很少使用的表单…

编写高质量的代码--基础:结构和样式,行为的分离

实现高质量的代码需要我们在结构和样式&#xff0c;行为的分离的基础上做到&#xff1a;精简&#xff0c;重用&#xff0c;有序。精简&#xff1a;尽量减小文件的大小&#xff0c;提高页面加载速度。重用&#xff1a;提高代码的重用性&#xff0c;减少冗余代码&#xff0c;提高…

提高Java的锁性能

Plumbr是唯一通过解释应用程序性能数据来自动检测Java性能问题的根本原因的解决方案。 几个月前&#xff0c;我们在Plumbr中引入了锁定线程检测之后&#xff0c;我们开始收到类似于“嘿&#xff0c;太好了&#xff0c;现在我知道是什么导致了性能问题&#xff0c;但是现在应该…

APK反编译工具

apktool dex2jar jd-gui 1、将要反编译的APK文件后缀改为.zip&#xff0c;解压 2、取出classes.dex文件&#xff0c;拷贝至dex2jar目录。 3、在dex2jar目录运行下列命令行&#xff1a;dex2jar.bat classes.dex&#xff0c;回车。 4、会发现该目录生成了classes.dex.dex2jar.j…

Dom属性方法

一、javascript的三大核心 1.ECMAScript js的语法标准 2.DOM Document object Model 文档对象模型&#xff0c;提供的方法可以让js操作html标签 3.BOM Browser Object Model 浏览器对象模型&#xff0c;提供的方法让js可以操作浏览器 注意&#xff1a;1. js里最大的boss是wind…

学习Netflix管理员–第2部分

为了继续上一篇有关Netflix Governator的一些基础知识的文章&#xff0c;在这里&#xff0c;我将介绍Netflix Governator带给Google Guice的另一项增强功能–生命周期管理 生命周期管理本质上提供了进入对象所经历的不同生命周期阶段的钩子&#xff0c;以引用有关Governor的Wi…

[置顶] UDP协议---心德(1)

UDP协议1.面向无连接 2.速度快 3.不可靠的协议&#xff0c;容易丢包 4.包小于64k DatagramSocket:此类表示用来发送和接收数据报包的套接字 DatagramPacket:数据包 发送端&#xff1a; 1.创建一个udpsocket服务 DatagrameSocket dsnew DatagramSocket(); 2.将数据封装到数据包…

@vue/cli 3 运行支持报错 socket

问题 /sockjs-node/info 无限报错解决方案 原因是相关代理端不支持 ws&#xff0c;因此需要在代理处关闭 ws&#xff0c;即 ws: false&#xff0c;如下&#xff1a;vue.config.js const ds_proxy {/: {ws: false,target: https://dev.test.gitinn.com/,changeOrigin: true,…