关于单元测试脚手架的几点思考

莱昂:Luc Besson的专业人士

莱昂:Luc Besson的专业人士

当我开始通过创建相同的对象并准备数据来运行测试来重复使用单元测试方法时,我对设计感到失望。 带有大量代码重复的长时间测试方法看起来并不正确。 为了简化和缩短它们,基本上有两个选项,至少在Java中:1)通过@Before@BeforeClass初始化的私有属性,以及2)私有静态方法。 他们俩对我来说都是反面向对象的,我认为还有另一种选择。 让我解释。

JUnit正式建议测试夹具 :

public final class MetricsTest {private File temp;private Folder folder;@Beforepublic void prepare() {this.temp = Files.createTempDirectory("test");this.folder = new DiscFolder(this.temp);this.folder.save("first.txt", "Hello, world!");this.folder.save("second.txt", "Goodbye!");}@Afterpublic void clean() {FileUtils.deleteDirectory(this.temp);}@Testpublic void calculatesTotalSize() {assertEquals(22, new Metrics(this.folder).size());}@Testpublic void countsWordsInFiles() {assertEquals(4, new Metrics(this.folder).wc());}
}

我认为该测试正在做什么很明显。 首先,在prepare() ,创建Folder类型的“测试装置”。 在所有三个测试中,将其用作Metrics构造函数的参数。 这里要测试的实际类是Metricsthis.folder是我们测试它所需要的。

这个测试怎么了? 有一个严重的问题:测试方法之间的耦合 。 测试方法(以及所有常规测试)必须彼此完全隔离。 这意味着更改一项测试不得影响任何其他测试。 在此示例中,情况并非如此。 当我想更改countsWords()测试时,必须更改before()的内部结构,这将影响测试“类”中的其他方法。

在充分尊重JUnit的情况下,在@Before@After中创建测试装置的想法是错误的,主要是因为它鼓励开发人员耦合测试方法。

这是我们可以改善测试并隔离测试方法的方法:

public final class MetricsTest {@Testpublic void calculatesTotalSize() {final File dir = Files.createTempDirectory("test-1");final Folder folder = MetricsTest.folder(dir,"first.txt:Hello, world!","second.txt:Goodbye!");try {assertEquals(22, new Metrics(folder).size());} finally {FileUtils.deleteDirectory(dir);}}@Testpublic void countsWordsInFiles() {final File dir = Files.createTempDirectory("test-2");final Folder folder = MetricsTest.folder(dir,"alpha.txt:Three words here","beta.txt:two words""gamma.txt:one!");try {assertEquals(6, new Metrics(folder).wc());} finally {FileUtils.deleteDirectory(dir);}}private static Folder folder(File dir, String... parts) {Folder folder = new DiscFolder(dir);for (final String part : parts) {final String[] pair = part.split(":", 2);this.folder.save(pair[0], pair[1]);}return folder;}
}

现在看起来好点了吗? 我们还没有,但现在我们的测试方法已完全隔离。 如果要更改其中一个,则不会影响其他参数,因为我将所有配置参数都传递给私有静态实用程序(!)方法folder()

一种实用方法,对吗? 是的, 闻起来 。

尽管比以前的设计要好得多,但这种设计的主要问题是它不能防止测试“类”之间的代码重复。 如果在另一个测试用例中需要类似Folder类型的测试治具,则必须将该静态方法移到那里。 甚至更糟的是,我将不得不创建一个实用程序类。 是的,在面向对象的编程中没有什么比实用程序类更糟糕的了。

更好的设计是使用“伪”对象而不是私有静态实用程序。 这是怎么回事。 首先,我们创建一个伪造的类并将其放入src/main/java 。 必要时,此类可用于测试以及生产代码中( Fk表示“伪造”):

public final class FkFolder implements Folder, Closeable {private final File dir;private final String[] parts;public FkFolder(String... prts) {this(Files.createTempDirectory("test-1"), parts);}public FkFolder(File file, String... prts) {this.dir = file;this.parts = parts;}@Overridepublic Iterable<File> files() {final Folder folder = new DiscFolder(this.dir);for (final String part : this.parts) {final String[] pair = part.split(":", 2);folder.save(pair[0], pair[1]);}return folder.files();}@Overridepublic void close() {FileUtils.deleteDirectory(this.dir);}
}

这是我们的测试现在的外观:

public final class MetricsTest {@Testpublic void calculatesTotalSize() {final String[] parts = {"first.txt:Hello, world!","second.txt:Goodbye!"};try (final Folder folder = new FkFolder(parts)) {assertEquals(22, new Metrics(folder).size());}}@Testpublic void countsWordsInFiles() {final String[] parts = {"alpha.txt:Three words here","beta.txt:two words""gamma.txt:one!"};try (final Folder folder = new FkFolder(parts)) {assertEquals(6, new Metrics(folder).wc());}}
}

你怎么看? 它不是比JUnit提供的更好吗? 它是否比实用程序方法更具可重用性和可扩展性?

总而言之,我认为单元测试中的脚手架必须通过与生产代码一起提供的伪造对象来完成。

翻译自: https://www.javacodegeeks.com/2015/05/a-few-thoughts-on-unit-test-scaffolding.html

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

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

相关文章

android 使用c 代码实现,JNI开发实现helloworld,调用自己的C代码实现(1)

JNI开发&#xff0c;实现自己的C代码&#xff0c;helloworld在这里实现一个简单的demo,完成加载自己的C代码使用Android studio&#xff0c;一步一步教你实现在屏幕上显示出helloworld如下图显示&#xff0c;配置号NDK的路径&#xff0c;没有路径的需要自己下载&#xff0c;在A…

使用WSO2 ESB进行邮件内容过滤

每个集成架构师或开发人员都应该熟悉Gregor Hohpe和Bobby Woolf所描述的企业集成模式&#xff08;EIP&#xff09; 。 模式之一是“内容消息过滤器” &#xff08;不要与消息过滤器模式混淆&#xff09;。 使用不同的Mediator在WSO2中有多种方法可以实现此目的。 一种方法是使…

BZOJ 1045 [HAOI2008]糖果传递 ★(环形等分:中位数)

题意 有n个小朋友坐成一圈&#xff0c;每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。 思路 假设平均数是x&#xff0c;且a1给an了k个&#xff08;k<0说明是an给a1了-k个&#xff09;&#xff0c;那么总代价就可以算出来&#xff1a; ananka1-…

android壁纸应用,HPSTR - 可能是你见过最会玩的壁纸应用 - Android 应用 - 【最美应用】...

今天这款 HPSTR 壁纸应用也不例外&#xff0c;HPSTR 主要的壁纸素材源来自 Unsplash(ios/android)、500px(android)、Reddit(android)这些素材源的图片都很优秀&#xff0c;特别是 Unsplash 它是著名的无版权图片网站。它家主要以风景为主&#xff0c;数量也足够多&#xff0c;…

android sqlite批量操作,Android: SQLite批量插入数据的最佳实践

大家都知道&#xff0c;Android里数据库用的是SQLite。在实际开发过程中&#xff0c;我们有时候会遇到批量插入数据的场景。这篇文章给大家分享一个小技巧&#xff0c;让批量插入数据达到最快的目的。首先&#xff0c;我先创建一个Table&#xff0c;里面只有一个字段&#xff1…

编写干净的测试–天堂中的麻烦

如果我们的代码有明显的错误&#xff0c;我们很有动力进行改进。 但是&#xff0c;在某些时候&#xff0c;我们认为我们的代码“足够好”并继续前进。 通常&#xff0c;当我们认为改进现有代码的好处小于所需的工作时&#xff0c;就会发生这种情况。 当然&#xff0c;如果我们…

使用Mockito时遇到的一些问题

最近在使用Mockito时遇到了几个比较tricking的问题&#xff0c;在这里记录一下。 1.如果方法的参数或者返回类型是泛型通配符相关的&#xff08;如<?>&#xff0c;<? extends XXX>&#xff09;&#xff0c;不管你定义的对象类型是否正确匹配&#xff0c;用any(ma…

c语言实现linux下的top命令来获取cpu利用率_有用的一篇笔记,linux 调优各项监控指标...

自开始负责生产环境部署&#xff0c;中间遇到了若干线上环境内存以及CPU的问题。由于微服务以及容器的流行&#xff0c;现在已经可以很方便的使用 K8s prometheus grafana alert 的方式进行监控&#xff0c;这足以覆盖大部分场景。最重要的事情已经交由最适合的组件去做&…

android config.mk,android编译分析之10—config.mk

config.mk可以说是android编译系统中关于配置环境的一个总的makefile&#xff0c;定义了编译环境的方方面面。执行完config.mk就完成了android编译系统的所有准备工作&#xff0c;即准备好了所有的编译需要的全局变量&#xff0c;下一步直接执行make&#xff0c;即可产生镜像文…

在Spring中记录JAX-WS SOAP消息

每当在Spring中使用JAX-WS时&#xff0c;您可能都希望记录传入和传出的SOAP消息-如果仅用于开发过程中的调试。 因此&#xff0c;第一件事就是增加日志级别&#xff0c;对吗&#xff1f; 不幸的是&#xff0c;这将无效。 您将要做的是利用javax.xml.ws.handler.HandlerResolver…

WordPress /wp-admin/includes/post.php user_ID 参数操作权限提升漏洞

漏洞版本: WordPress 3.6 漏洞描述: Bugtraq ID:62346 CVE ID:CVE-2013-4340WordPress是一种使用PHP语言开发的博客平台&#xff0c;用户可以在支持PHP和MySQL数据库的服务器上架设自己的网志WordPress wp-admin/includes/post.php脚本在处理user_ID参数时存在一个安全漏洞&…

rip协议中周期性广播路由信息的报文_技术实操||距离矢量路由协议-RIP

距离矢量路由协议—RIP01距离矢量路由协议概述路由信息协议RIP(RoutingInformation Protocol)的简称&#xff0c;它是一种基于距离矢量(Distance-Vector)算法的协议&#xff0c;使用跳数作为度量来衡量到达目的网络的距离。RIP主要应用于规模较小的网络中。RIP是一种比较简单的…

android中可以有两个焦点吗,android – 如何通过焦点在屏幕上调整两个片段的大小?...

我有三个片段,前两个填充80&#xff05;的屏幕,最后一个填充其余的片段(这个片段永远不会改变大小).我希望,在用户(焦点)输入片段后,调整片段的大小,使其填满屏幕的70&#xff05;(将10&#xff05;留给另一个).像这样&#xff1a;可以通过动态改变碎片的重量吗&#xff1f;或者…

使用tinylog 1.0简化您的日志记录

tinylog的大小仅为75 KB&#xff0c;是广泛使用的经典日志记录框架Log4j和Logback的轻型替代方案。 经过三年的开发&#xff0c;最终版本1.0刚刚于 3月底发布 。 在几个设计问题中&#xff0c;tinylog采取了与Java中经典日志记录框架完全不同的方法。 本文将介绍与Log4j和Logba…

MySQL : 报错:1130-host ... is not allowed to connect to this MySql server 开放mysql远程连接 不使用localhost...

MySQL : 报错:1130-host ... is not allowed to connect to this MySql server 开放mysql远程连接 不使用localhost 摘自: http://www.cnblogs.com/xyzdw/archive/2011/08/11/2135227.html 报错:1130-host ... is not allowed to connect to this MySql server 解决方法&#x…

华谊兄弟出现什么问题_什么是语言训练?这就要从语言问题的出现说起了

开口、发音是每一个孩子在语言发展过程中所不可少的经历&#xff0c;他们从周围环境中获取到的各种信息转化为想要表达的内容。虽然一开始孩子的语言并没有成年人那么流畅和准确&#xff0c;但随着时间的推移&#xff0c;他们的说话发音愈发成熟。只是&#xff0c;并不是所有孩…

【算法提升—力扣每日一刷】五日总结【12/18--12/22】

文章目录 2023/12/18LeetCode每日一刷&#xff1a;[20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) 2023/12/19LeetCode每日一刷&#xff1a;[150. 逆波兰表达式求值&#xff08;后缀表达式运算&#xff09;](https://leetcode.cn/problems/evaluate-rever…

CompletableFuture不能被打断

我已经写了很多有关InterruptedException和中断线程的文章 。 简而言之&#xff0c;如果您没有Future.cancel()调用Future.cancel()那么Future将终止待处理的get() &#xff0c;但还将尝试中断基础线程。 这是一个非常重要的功能&#xff0c;可以更好地利用线程池。 我还写信总…

Nginx 禁止部分 User-Agrent 访问

经常有一些垃圾爬虫&#xff0c;完全不管你受得了受不了&#xff0c;完全不管你的 robots.txt &#xff0c;拼命的爬你的网站&#xff0c;用下面方面可以帮这帮垃圾干掉。 location / { root /home/www/; if ($http_user_agent ~* "qihoobot") { retu…

crio电压采集 labview_NI cDAQ917采集温度方法

NI cDAQ-9171是一款由总线供电的单槽NI CompactDAQ USB机箱&#xff0c;适合较小的便携式传感器测量系统。cDAQ-9171可与50多款专用测量模块配合使用&#xff0c;用于构建模拟输出、数字I/O或计数器/定时器测量系统。这些模块适用于各种传感器测量&#xff0c;包括热电偶、RTD、…