开源中国

我们不支持 IE 10 及以下版本浏览器

It appears you’re using an unsupported browser

为了获得更好的浏览体验,我们强烈建议您使用较新版本的 Chrome、 Firefox、 Safari 等,或者升级到最新版本的IE浏览器。 如果您使用的是 IE 11 或以上版本,请关闭“兼容性视图”。
单元测试里的 5 个错误 - 技术翻译 - 开源中国社区

单元测试里的 5 个错误 【已翻译100%】

标签: JUnit
oschina 推荐于 4年前 (共 3 段, 翻译完成于 02-21) 评论 13
收藏  
55
推荐标签: JUnit 待读
参与翻译 (1人) : lwei 仅中文 | 中英文对照 | 仅英文 | 打印此文章

当我第一次听说可以使用框架比如JUnit来进行单元测试的时候,我惊叹这真是一个简单而强大的概念。它取代了随机测试,使你可以保存你的测试代码,并按照需要随时运行它们。按照我的理解,关于单元测试并没有多少产生误解的可能。但是过去的几年中,我确实见过几种或多或少不太正确的单元测试使用方式。这里按照重要程度,列出5条:

1. 跟协作逻辑一起来测试算法。如果跟协作逻辑代码分离开来,那么算法逻辑是最容易测试的(参见选择性单元测试 – 代价和好处)。否则在你的逻辑被测试之前,你就不得不先进行诸如通过任务队列提交一个任务之类的工作。 任务队列部分只会使事情变得复杂。除非你想测试任务队列本身,否则你就应当把调用run方法时所执行的逻辑剥离开来,并对它进行单独测试。那样,不论是编码还是测试都会更易于编写和管理。

lwei
 翻译得不错哦!

2. Mock测试太多。也许单元测试的最大好处就是它迫使你编写能够独立测试的代码。也就是说,你的代码会变得模块化。当你把你要处理的对象的周围的一切都模拟了,就没有什么能迫使你去把各部分分离开来。你会发现这样写出的代码,你很难在外围添加独立的部分 – 因为所有东西都纠缠在一起。Bill Wake最近发推说: ”真是讽刺 – 模拟测试框架越强大,你在改进设计时所感受到的压力就会越小。”

3. 不使用断言。有时我会看到一些测试,里面创建了一个对象,调用了一些方法,然后,就没有然后了。也许它是在循环里这样做的,而且在创建和调用上会有些差异。但是,却没有用断言来做任何检查。这就完全失去了意义 – 没有检查你的代码是否按照预期进行工作的。当然,代码是运行了,但是仅此而已。如果抛出了一个异常,我们会注意到它,但是却不会验证其它任何事情。

lwei
 翻译得不错哦!

4. 在测试代码中遗留print语句。我把这视为手工测试的后遗症 – 你希望看到对象的值来判断它们是否正确。但是所有的检查都应当使用断言来完成。如果单元失败了,你也能看到它,因为这个测试也会失败。当测试通过时,什么也不应当打印出来。在编写测试代码时,使用print语句有时是有用的。但是在需要用print的地方应当设置一个标志位,用来在进行测试的时候屏蔽它。

5. 查看日志信息,而不是运行结果。 还好这并不普遍,但是我却见过一个非常有能力的开发人员这么干过。要知道,真正重要的是方法的运行结果,而不是日志中都打印了什么,因为即使代码中有错误,测试也可能会通过。好了,说的很明白了。

后面3个问题都很容易规避。头2个问题则需要付出更多努力,但是会得到良好分离的代码。祝测试愉快!

lwei
 翻译得不错哦!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
评论(13)
Ctrl/CMD+Enter

模块化
个人觉得日志信息也很重要,可以发现很多隐性bug
诚信请教,老代码怎么单元测试。
背景是这样的,我有一份老代码,大概有20K行的一个类,里面还有许多if-else和8层以上的深度的for。
不知道怎么mock或者单元测试好,我只能不停的print了。
这样的代码先把这个类重构下,函数能分的分,类可拆的拆,重构好了再写单元测试。
日记很重要,这些文章不可完全信,误人子弟啊!
2, 4, 5工作中全有这些问题,而且还是大大的
5有点问题啊.
一段代码,也许某个过程有错误,但是输出结果正确.如果不吧这个错误变为可控的,那很可能这个错误就隐藏一个BUG. 看过程上的错误, 要么断点,要么日志吧. 个人感觉, 开发者必须要让代码的全过程可预知, 而仅仅结果正确
想到个方法,防止print遗漏后不会留下问题,就是自己重写个类print的,并且该方法在debug没开启时是不会有任何输出的
"跟协作逻辑一起来测试算法。" 到底有什么不好, 能举个具体的实例吗? 谢谢
一个系统本来就是各个逻辑息息相关. 用户用一个系统的时候,各个逻辑都在发挥着不同的功能, 确保每个逻辑没有问题,但是你能确保每个逻辑连起来时,就没有问题吗?

引用来自“Doer”的评论

这样的代码先把这个类重构下,函数能分的分,类可拆的拆,重构好了再写单元测试。

这不是不准我改嘛。
“5. 查看日志信息,而不是运行结果”
一般来说确实不应该手动去查看日志信息。但我认为依旧有其他情况需要这么做:该测试用例的目的就是为了测试错误处理流程。错误及异常处理严格来说也属于程序的重要部分,只是大部分时候没有得到足够的重视。正确的错误处理,才能保证产品在运作的过程中得到有效的记录。否则,你就丧失了尽早发现先和修复漏洞的机会。

引用来自“开源中国匿名会员”的评论

引用来自“Doer”的评论

这样的代码先把这个类重构下,函数能分的分,类可拆的拆,重构好了再写单元测试。

这不是不准我改嘛。

对于遗留系统的测试覆盖确实很难保证,所以明智的团队对遗留代码的测试覆盖率要求并不高。如果不让改的话,那你算是遇上烂茬儿了……跟上面建议建议对单元测试的规定做些合理调整吧。
顶部