关于单元测试脚手架的几点思考
莱昂: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
构造函数的参数。 这里要测试的实际类是Metrics
而this.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
关于单元测试脚手架的几点思考相关推荐
- vue 脚手架测试环境_关于单元测试脚手架的几点思考
vue 脚手架测试环境 莱昂:Luc Besson的专业人士 当我开始通过创建相同的对象并准备用于运行测试的数据来重复进行单元测试方法时,我对设计感到失望. 带有大量代码重复的长测试方法看起来并不正确 ...
- 单元测试之道——基于junit的java单元测试 的读书笔记与思考
第二章 你的首个单元测试 这一张已经忘了差不多,如何去测试,其实首先还是得先去考虑怎么去测试,这个就需要看代码单元的需求了. 一个简单的例子.测试排序 第二章 你的首个单元测试 这一张已经忘了差不多, ...
- 如何对 Jenkins 共享库进行单元测试
2019独角兽企业重金招聘Python工程师标准>>> 本文首发于:Jenkins 中文社区 Jenkins 共享库是除了 Jenkins 插件外,另一种扩展 Jenkins 流水线 ...
- javascript 单元测试迷思
非前端,偶尔写写javascript,上一篇博文的代码,被发现单元测试不足导致bug. 思考了一下,写个了自动化测试脚本 var testData = [{param:'19900101',retVa ...
- 微软西雅图总部DevOps交流总结
本文转自Study4台湾社区.Study4台湾社区,成立于2011/9/25,希望藉由社群推广的力量,让台下的朋友听到来自不同县市的大师讲课,也让台上年轻一辈的技术传教士能不断的琢磨并且追上大师这是一 ...
- 小白成长建议(9)-苞丁解牛
单元测试 估计对于小白来说,一提到单元测试就是开发.开发.开发,好深奥.好难.但是我想说,单元测试可能是所有测试中最简单的了,想反系统测试可能是最难的,只是所谓的开发门槛让测试人员有些抵触而已. 为何 ...
- Java 技术栈的变迁是如何深受敏捷影响的?
作者:熊节 / 插画:虎头锤 以 Spring 为代表的轻量级 J2EE 架构方案,不仅是一种技术方案,并且内蕴了与敏捷方法一脉共通的价值观.轻量级 J2EE 与 EJB 的技术方案之争,背后是瀑布与 ...
- vue-cli5脚手架搭建项目过程详解 -vue组件单元测试
简介 单元测试是对软件中的最小可测试单元进行测试.(最小可测试单元是要有结果产出的.例如某个方法,单独的某个操作) 单元测试其实是伴随着敏捷开发,它是对更快开发的一种追求.早发现错误比晚发现错误会更好 ...
- QTest 单元测试框架及单元测试思考
文章目录 1. 单元测试思考 引用1: 引用2: c/c++的单元测试框架 2. Qt的单元测试框架 QTest 2.1 Qt Test特性 2.3 使用QMake构建单元测试 2.4 QTest 命 ...
最新文章
- JavaScript规范
- FEMS综述: 如何从微生物网络中的“毛线球”理出头绪(3万字长文带你系统学习网络)...
- linux ssh和sftp区别,使用 SSH 和 SFTP 协议
- HDLBits答案(22)_基于有限状态机的计数器
- [BZOJ3529][Sdoi2014]数表
- 特殊表情存数据库处理
- Visual Studio Code打开项目
- virtualbox版oracle RAC环境搭建
- Robolectric 探索之路
- python 什么时候后面要加冒号_Python中的每个if条件语句后面都要使用冒号。
- ArcGIS制图表达Representation实战篇1-边界线和行道树制作
- 全文检索技术 mysql_浅谈MYSQL的全文检索的应用
- jfreechart柱状图java mysql_时序时空数据库MySQL再升级,兼容MySQL协议
- 五种常用手机Java编程软件
- wpf使用Chart控件绘制线图
- JavaScript动态生成表格
- 结构体初始化、结构体指针、结构体数组
- Matlab中gca、gcf、gco区别
- 微型计算机软件系统分为什么,微型计算机软件微型计算机软件主要包括哪些软件?...
- 常用的页面布局(两栏布局、三栏(圣杯、双飞翼)布局)
热门文章
- ssh(Spring+Spring mvc+hibernate)——applicationContext.xml
- hibernate正向生成数据库表以及配置——Teacher.java
- 数组的初始化与默认值
- 2017蓝桥杯省赛---java---B---9(分巧克力)
- Android碎片Fragment详讲(1)
- python 高维数据_Python数据分析入门|利用NumPy高效处理高维数据
- 旅游系统_数字洛江智慧旅游系统助力提升旅游安全水平
- python oj 输入_Python写OJ题时输入问题
- python数据分析架构_Python数据分析
- java 用流创建流_成为Java流大师–第1部分:创建流