谨慎使用JUnit的预期异常

有时,当我们收到对jOOQ或其他库的拉取请求时,人们会将单元测试中的代码更改为更“惯用的JUnit”。 特别是,这意味着他们倾向于更改此代码(公认的不是那么漂亮的代码):

@Test
public void testValueOfIntInvalid() {try {ubyte((UByte.MIN_VALUE) - 1);fail();}catch (NumberFormatException e) {}try {ubyte((UByte.MAX_VALUE) + 1);fail();}catch (NumberFormatException e) {}
}

…成为“更好”和“更清洁”的版本:

@Test(expected = NumberFormatException.class)
public void testValueOfShortInvalidCase1() {ubyte((short) ((UByte.MIN_VALUE) - 1));
}@Test(expected = NumberFormatException.class)
public void testValueOfShortInvalidCase2() {ubyte((short) ((UByte.MAX_VALUE) + 1));
}

我们获得了什么?

没有!

当然,我们已经必须使用@Test批注,因此我们不妨使用其expected的属性对吗? 我声称这是完全错误的。 有两个原因。 当我说“两个”时,我的意思是“四个”:

1.在代码行数方面,我们并没有真正获得任何好处

比较语义上有趣的位:

// This:
try {ubyte((UByte.MIN_VALUE) - 1);fail("Reason for failing");
}
catch (NumberFormatException e) {}// Vs this:
@Test(expected = NumberFormatException.class)
public void reasonForFailing() {ubyte((short) ((UByte.MAX_VALUE) + 1));
}

给定或采用空格格式,基本语义信息量完全相同:

  1. 该方法正在测试中的ubyte() 。 这不会改变
  2. 我们要传递给失败报告的消息(以字符串或方法名称表示)
  3. 异常类型和预期的事实

因此,即使从样式角度来看,这也不是真正有意义的更改。

2.我们还是必须将其重构

在注释驱动的方法中,我所能做的就是测试异常类型 。 例如,在以后要添加更多测试的情况下,我无法对异常消息做出任何假设。 考虑一下:

// This:
try {ubyte((UByte.MIN_VALUE) - 1);fail("Reason for failing");
}
catch (NumberFormatException e) {assertEquals("some message", e.getMessage());assertNull(e.getCause());...
}

3.单个方法调用不是单位

单元测试称为testValueOfIntInvalid() 。 因此, 通常在输入无效的情况下,要测试的语义“单位”是UByte类型的valueOf()行为的语义“单位”。 不适用于单个值,例如UByte.MIN_VALUE - 1

不应将其拆分为更小的单元,仅因为这是我们将@Test注释塞入其功能范围的唯一方法。

TDD员工,请听此。 我从不希望将我的API设计或我的逻辑塞进“落后”测试框架(没有个人的,JUnit)所施加的一些怪异的限制中。 永不 ! “我的” API比“您的”测试重要100倍。 这包括我不想:

  • 公开一切
  • 使一切都没有定论
  • 使一切都能注射
  • 使所有内容均为非静态
  • 使用注释。 我讨厌注解。

不。 你错了。 Java已经不是一种太复杂的语言,但是让我至少可以以我想要的任何方式使用它提供的一些功能。

不要因为测试而在我的代码上强加您的设计或语义上的毁损。

好。 我反应过度了。 我总是在存在批注的情况下 。 因为…

4.对于控制流结构而言,注释始终是错误的选择

一次又一次,我为Java生态系统中的注释滥用而感到惊讶。 注释对三件事有好处:

  1. 可处理的文档(例如@Deprecated
  2. 方法,成员,类型等的自定义“修饰符”(例如@Override
  3. 面向方面的编程(例如@Transactional

并且要注意,@ @Transactional是使其成为主流的少数几个真正有用的方面之一(日志挂钩是另一个方面,或者,如果绝对必须的话,依赖注入)。 在大多数情况下,AOP是解决问题的利基技术,您通常在普通程序中不希望这样做。

用注解对控制流结构进行建模绝对不是一个好主意,更不用说测试行为了

是。 Java已经采用了很长的(缓慢的)方法来包含更复杂的编程习惯用法。 但是,如果您对单元测试中偶尔的try { .. } catch { .. }语句的冗长性感到不满,那么您可以找到解决方案。 是Java 8。

如何使用Java 8更好地做

JUnit lambda正在开发中: http : //junit.org/junit-lambda.html

他们向新的Assertions类添加了新的功能API: https : //github.com/junit-team/junit-lambda/blob/master/junit5-api/src/main/java/org/junit/gen5/api /Assertions.java

一切都基于Executable功能接口 :

@FunctionalInterface
public interface Executable {void execute() throws Exception;
}

该可执行文件现在可以用于实现断言引发(或不引发)异常的代码。 请参见Assertions的以下方法

public static void assertThrows(Class<? extends Throwable> expected, Executable executable) {expectThrows(expected, executable);
}public static <T extends Throwable> T expectThrows(Class<T> expectedType, Executable executable) {try {executable.execute();}catch (Throwable actualException) {if (expectedType.isInstance(actualException)) {return (T) actualException;}else {String message = Assertions.format(expectedType.getName(), actualException.getClass().getName(),"unexpected exception type thrown;");throw new AssertionFailedError(message, actualException);}}throw new AssertionFailedError(String.format("Expected %s to be thrown, but nothing was thrown.", expectedType.getName()));
}

而已! 现在,那些反对try { .. } catch { .. }块的冗长的人可以重写此代码:

try {ubyte((UByte.MIN_VALUE) - 1);fail("Reason for failing");
}
catch (NumberFormatException e) {}

…变成这样:

expectThrows(NumberFormatException.class, () -> ubyte((UByte.MIN_VALUE) - 1));

如果我想对异常进行进一步检查,可以这样做:

Exception e = expectThrows(NumberFormatException.class, () -> ubyte((UByte.MIN_VALUE) - 1));
assertEquals("abc", e.getMessage());
...

出色的工作,JUnit lambda团队!

函数式编程每次都会击败注释

注释被滥用了很多逻辑 ,主要是在JavaEE和Spring环境中,它们都迫切希望将XML配置移回Java代码。 这是错误的方法,这里提供的示例清楚地表明,与使用批注相比,几乎总是有一种更好的方法可以使用面向对象或功能编程来显式地写出控制流逻辑。

@Test(expected = ...)的情况下,我得出结论:

安息, expected

(无论如何,它不再是JUnit 5 @Test批注的一部分)

翻译自: https://www.javacodegeeks.com/2016/01/use-junits-expected-exceptions-sparingly.html

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

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

相关文章

plupload使用例子

plupload使用例子1. 例子 <li><a id"uploadFile">上传</a></li>//文书上传和显示 $(function () {var uploader new plupload.Uploader({runtimes: html5,flash,silverlight,html4,// 指定上传方式browse_button: uploadFile,unique_names…

mysql获取相隔时间段的数据

思路&#xff1a;为时间段内的数据进行编序号&#xff0c;然后计算好相隔时间&#xff0c;拿到id作为搜索条件 SELECT * FROM ( SELECT (i:i1) as i, id, data_send_time FROM jl_pims_machine_time mt,(select i:0) as it where mt.company_id 1001 AND mt.machine_id 1 ord…

bom实现方块移动_从0开始实现一个俄罗斯方块

写在前面得话&#xff1a;这篇文章主要记录了我是怎么一步一步写出俄罗斯方块&#xff0c;整个代码用的函数编程&#xff0c;主要是为了让一些不熟悉es6, 面向对象写法得 新手能更容易看明白&#xff0c;全部得代码中都是一些js的基础知识&#xff0c;很容易理解。要说有点麻烦…

字符串工具类

字符串工具类import javax.servlet.http.HttpServletRequest; import java.util.UUID;public class CommonUtil {/*** param request 请求* return java.lang.String 返回路径* description 获取绝对路径* date 2021/7/14 20:45*/public static String getUrlPath(HttpServletR…

JSonP跨域请求

JSonP跨域请求 我们在通过自己的页面或程序通过ajax请求其它网站或服务时&#xff0c;会存在一个ajax直接请求普通文件存在跨域无权限访问的问题&#xff0c;甭管你是静态页面、动态网页、web服务、WCF&#xff0c;只要是跨域请求&#xff0c;一律不准。不过我们又发现&#xf…

cli3解决 ie11语法错误 vue_基于 Vue + Koa2 + MongoDB + Redis 实现一个完整的登录注册...

项目地址&#xff1a;https://github.com/caochangkui/vue-element-responsive-demo/tree/login-register通过 vue-cli3.0 Element 构建项目前端&#xff0c;Node.js Koa2 MongoDB Redis 实现数据库和接口设计&#xff0c;包括邮箱验证码、用户注册、用户登录、查看删除用户…

gwt 嵌入html_GWT和HTML5画布演示

gwt 嵌入html这是我对GWT和HTML5 Canvas的第一个实验。 我的第一个尝试是创建矩形&#xff0c;仅用几行代码就得出了这样的内容&#xff1a; 码&#xff1a; public class GwtHtml5 implements EntryPoint {static final String canvasHolderId "canvasholder";sta…

使用UIWebView载入本地或远程server上的网页

大家都知道&#xff0c;使用UIWebView载入本地或远程server上的网页&#xff0c;sdk提供了三个载入接口&#xff1a;- (void)loadRequest:(NSURLRequest *)request; - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL; - (void)loadData:(NSData *)data MI…

css使按钮固定在界面上面

css使按钮固定在界面上面<div><div style"border-bottom: 1px solid #e7e7e7"><a class"" onclick"saveTable()" style"margin-left: 2%"><i class""></i>保存</a><a class"&q…

Spring MVC:Trgger手动验证表单对象

有时可能需要在Spring MVC Controller中使用手动验证。 使用Spring的org.springframework.validation.ValidationUtils类非常简单。 了解如何在两种不同的情况下调用验证器。 方案1 –调用验证 在这种情况下&#xff0c;我有一个带有用户名字段的用户表单。 用户名字段使用自定…

tez什么意思_传统数仓和大数据数仓的区别是什么?

概念与容器为什么先说这个&#xff0c;其实很简单&#xff1a;因为绝大多数人都把这两个概念混为一谈。然后就会出现各种各样的问题&#xff1a;oracle不是数据库么&#xff0c;怎么又是数据仓库&#xff1f;Hive不是数据仓库么&#xff1f;怎么又是数据库&#xff1f;数据仓库…

Ajax4Jsf 简单介绍

Ajax4jsf 允许开发人员将 Ajax 功能添加到 JSF 应用程序中&#xff0c;而不需要 JavaScript 或用 Ajax 图形部件替换现有的组件。这个包还允许在使用 Java 2D 库时动态地生成图像。Ajax 是一种编程技术&#xff0c;它处理只有页面的一部分需要处理而不需要重新装载整个页面的情…

华为M2平板打不开云课堂_能运行PC应用的安卓生产力平板:华为MatePad Pro 5G登场...

当手机屏幕无法承担更复杂的工作任务&#xff0c;当PC重量不能满足更随性的移动办公&#xff0c;拥有全面屏和便携优势的平板电脑或是中间值&#xff0c;但前提是其必须拥有足够强大的生产力。5月27日华为在国内上市的其首款5G平板——华为MatePad Pro 5G&#xff0c;就是5G时代…

或许你不知道的10条SQL技巧(转自58沈剑原创)

这几天在写索引&#xff0c;想到一些有意思的TIPS&#xff0c;希望大家有收获。 一、一些常见的SQL实践 &#xff08;1&#xff09;负向条件查询不能使用索引 select * from order where status!0 and stauts!1 not in/not exists都不是好习惯 可以优化为in查询&#xff1a; se…

dhtmlXGrid复选框点击事件

dhtmlXGrid复选框点击事件var mygrid; //加载初始界面 $(function () {mygrid new dhtmlXGridObject(colour);mygrid.setImagePath(getUrlPath() "/static/plugg/dhtmlx/dhtmlxGrid/codebase/imgs/");mygrid.setHeader("#master_checkbox,状态,查看,编辑,xxx,…

soa示例_SOA示例应用程序

soa示例SOA描述了一组用于创建松散耦合的&#xff0c;基于标准的&#xff0c;与业务相关的服务的模式&#xff0c;由于描述&#xff0c;实现和绑定之间的关注点分离&#xff0c;因此提供了新的灵活性。 近年来&#xff0c;至少在参与大多数信息技术活动的人们中&#xff0c;面向…

阿里云图片剪裁

ng-src"{{(buttomImg.imgUrl176h_632w_1e_1c)}}" alt"Space" 转载于:https://www.cnblogs.com/karila/p/7205967.html

body curl 设置post_curl 命令详解

常用参数常用参数分类# 调试类-v, --verbose 输出信息-q, --disable 在第一个参数位置设置后 .curlrc 的设置直接失效&#xff0c;这个参数会影响到 -K, --config -A, --user-agent -e, --referer-K, --config FILE …

sql语句lastupdate使用数据库库函数

sql语句lastupdate使用数据库库函数<sql id"Base_Column_List">CKLSH, ZJLX, ZJHM, MC, CBR, SJY, HJSZD, GJ, ZT, AH, FYDM, DJPC, LASTUPDATE, SSDW</sql><insert id"saveCkdx">INSERT INTO CK_CKDX(<include refid"Base_Colu…

NetBeans Java EE技巧7:忽略的Java类和XHTML编辑器快捷方式

有时&#xff0c;最被忽略的是IDE最有用的功能。 在本文中&#xff0c;我将概述在开发Java EE应用程序时可以使用的五个NetBeans Java和XHTML编辑器快捷方式。 &#xff03;1 –轻松修复命名空间和类 也许您已经向尚未声明名称空间的视图中添加了新的JSF标记&#xff0c;或者…