作者 | S.L

来源 | http://r6d.cn/aaTem

关于测试

1 测试都包括哪些

广义的测试包括 UT、IT、压力测试、硬件测试等等,这里重点讨论 Unit Test 即单元测试。

2 啥是 UT

单元测试(又称为模块测试, Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。

简而言之就是覆盖你的代码的一些测试用例,不依赖于任何第三方的服务依赖,如 HTTP 接口、数据库连接等,只测试功能不依赖于环境,在任何时候人和机器上都可以 Pass。

3 为什么要写 UT

让你的代码质量更可靠&让你对代码结构更加敏感&迫使你写更优质的代码&…

4 为什么不写 UT

!${为什么要写 UT}

5 什么在阻止你写 UT

  • 代码本身的原因

    • 如果代码复杂度较高还缺少必要的抽象和拆分,就会让人对写 UT 望而生畏。

  • 编码工作量的原因

    • 无论是用什么样的单元测试框架,最后写出来的单元测试代码量也比业务代码只多不少,在不作弊的前提下要保证相关的测试覆盖率,大概要三倍源码左右的工作量。

  • 难以维护的原因

更多的代码量,加上单测代码并不像业务代码那样直观,还有对单测代码可读性不重视的坏习惯,导致最终呈现出来的单测代码难以阅读,要维护更是难上加难。

6 合格的 UT 什么样

至少要满足:

  • 测试的是一个代码单元内部的逻辑,而不是各模块之间的交互。

  • 无依赖,不需要实际运行环境就可以测试代码。

  • 运行效率高,可以随时执行。

Java 如何写 UT

Java 开发一般都是用 JUnit 或 TestNG,我们大多人还是使用 JUnit4。本文不讨论语法,只介绍一般性的使用规范。

7 命名

可以参考 7 Popular Unit Test Naming ( https://dzone.com/articles/7-popular-unit-test-naming )

8 Assertion

任何一个 UT 中需要至少包含一个 assert,用 System.out.println()来验证结果不符合 UT 的规范,一般都是验证方法的返回结果,如 assertEquals(200, statusCode)而不是 System.out.println(200==statusCode)。

Assertion 只能保证走过的分支的结果是否正确,无法保证一定是走过了某些分支。

9 为啥要 Mock

不用 Mock 我们自己也能实现测试(如匿名类),只不过对代码的要求非常高

10 Mock 框架

一些常用的 mock 库包括 Mockito、JMockIt、EasyMock、PowerMock…没有优劣没有好坏,只有合适与否。

比如我个人比较喜欢 Mockito:

  • 第一它相对于其他几个老牌库来说比较新并且更新活跃,在 github 中引用的也最多

  • 第二它的 fluent API 风格的代码可读性很高跟 JDK8 的 Stream 风格很像

  • 第三它抽象出测试中的经典概念,如 when().thenReturn()、doThrow().when()、verify()、times()、never()以及各种注解很容易理解

11 什么样的方法需要 mock

  • 任何被非本类的功能均需要 mock,如数据库访问、RPC 接口、外部引入的 jar 包等

  • 环境变量、系统属性和方法

  • 测试只测试当前类当前方法的功能,依赖方的功能由依赖方的 UT 来保证正确性,本层不负责验证

  • mock 本质上是一个 proxy,在需要提供功能的时候由开发者提供“伪实现”

12 什么样的方法不需要 mock

  • 本类的需要测试的方法依赖的同类方法,该方法的正确性由该方法自身的 UT 来保证

  • 静态方法,静态方法由自身的 UT 来保证功能的正确性

  • protected 方法是可以测试的,只要测试代码类和要测试的类在同一个 package 下面就可以

  • private 方法(有异议),我的看法是私有方法如果逻辑很多,应该重构出来提供 public 方法或者新的 Class 进行重构;如果逻辑不多仍然保证不了无 bug ,可以使用反射来测试。其实 private 方法的测试是需要通过对 public 方法的测试来完成的,因为 private 方法总是会被 public 方法调用的。还有一种测试方法就是放宽访问限制,private 方法改为 protected,并且用 guava 的 @VisibleForTesting 注解标注放宽权限的方法。

13 如何设计适合测试的接口

  • 1.Dependency Injection

如果把一种依赖写死在方法里肯定不利于测试,如果该依赖是一种强引用第三方服务的 sdk 你就痛苦了,如配置类初始化时需要连接 zk 且无法注入

  • 2.Abstraction

包括类的抽象、方法的提取,代码越精简,测试越方便、越快速、越容易暴露问题

  • 3.开闭原则

面向扩展开发,面向修改闭合,不对老代码入侵,避免 UT 重复修改

  • 4.慎重声明 static 方法

最好的 static 方法是完全不依赖任何第三方服务自己可以实现业务逻辑的代码,如果依赖第三方,使用 reference 传入而不是写死在 class 或 method 里

  • 5.测试类而不是实现

单元测试测试的对象是类,测试类的功能在各种情况下是否符合预期,而不是测试实现。所以我们只需要测试能够跟其他类交互的 public 方法就可以了。这样的一个好处就是,如果哪天需要重构代码的实现,或者换一个算法实现某些方法,但功能不变的情况下,UT 是可以复用的。如果针对实现来测试,如果哪天要重构代码实现,那 UT 就会 fail 掉。

  • ……待续……

测试覆盖率

一个仁者见仁智者见智的问题,不做深入讨论了。

个人建议工具方法(保证正确性以及边界条件不出错)、核心流程(复杂的条件判断尤其需要 UT 保证)需要重点覆盖,底层接口如 DAO、简单的 Service 封装可以不用写。

IDEA Plugin

推荐一个 JUnitGeneratorV2.0,可以通过 Command+N 来生成 Test 类或者直接在类名上使用 alt+enter 来生成。

总结

没有测不了的代码,只有测试不够方便的代码,大多源于设计不够合理。

写单元测试的难易程度跟代码的质量关系最大,并且是决定性的。项目里无论用了哪个测试框架都不能解决代码本身难以测试的问题,所以如果你遇到的是“我的代码里依赖的东西太多了所以写不出来单测”这样的问题的话,需要去看的是如何设计和重构代码,而不是这篇文章。

Reference

  • https://dzone.com/articles/7-popular-unit-test-naming ( https://dzone.com/articles/7-popular-unit-test-naming )

  • https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2 ( https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2 )

点击下方卡片关注我,订阅更多精彩内容

往期推荐

“智能”坐垫记录离座时间,是高科技福利还是又一个员工压榨机器?

Java延迟加载的最佳实践应用示例!

新年新气象,该换一波壁纸了!

不容错过的灰度发布系统架构设计

还在封装各种 Util 工具类?这个神级框架帮你解决所有问题!

阿里开源台柱 Ant Design 源码仓库被删了...

合格的后端Coder都应该写好UT和Mock测试相关推荐

  1. 后端开发都应该了解点接口的压力测试(Apache Bench版)

    背景 小A:小B,最近调你的接口老是超时呀,8秒都还没返回结果,是不是有性能问题呀! 小B :我看看~~ 类似这样的对话,在现实中是时有发生的,不是特别严重的话,往往大家也不会去重视这个事. 尤其是在 ...

  2. 最近工程师怎么都在写公众号?这玩意到底能赚多少钱?

    " 阅读本文大概需要 3 分钟. " 文章来源于进击的Coder,作者研究生小马 就是,前段时间嘛,公众号交流群,有一哥看我天天兢兢业业分享推送链接,提出了振聋发聩的问题 &quo ...

  3. 华为java一个月写多少行代码_[财经]阿里员工吐槽华为:面试官1万行代码都没写过? - 南方财富网...

    5月7日,有疑似阿里员工在社交网络上爆料称,打算跳槽华为,但是去面试后,真的是太失望,因为面试官真的是太水了. 从这位网友晒出的帖子看,一名阿里的员工面试华为云后端开发的岗位,但过程并不顺利,因为面试 ...

  4. python编程可视化小程序_人人都可以写的可视化Python小程序第二篇:旋转的烟花...

    兴趣是最好的老师 枯燥的编程容易让人放弃,兴趣才是最好的老师.无论孩子还是大人,只有发现这件事情真的有趣,我们才会非常执着的去做这件事,比如打游戏.如果编程能像玩游戏一样变得有趣,我相信很多人就特别愿 ...

  5. 后端接口都测试什么?要怎么测?

    作者:Glen.He 来源:http://www.cnblogs.com/puresoul/ 本文主要分为两个部分: 第一部分: 主要从问题出发,引入接口测试的相关内容并与前端测试进行简单对比,总结两 ...

  6. 为什么程序员都不写文档?

    ‍‍‍ ‍ [CSDN 编者按]对于程序员来说文档可能是他最大的软肋.一些被称之为高手的程序员,往往是文档方面的处理会偏弱.不管这个程序员是在大公司.还在小公司.不管程序是写文档的.还是不写文档的,大 ...

  7. 使用python完成的一个烟花小程序-人人都可以写的可视化Python小程序第二篇:旋转的烟花...

    兴趣是最好的老师 枯燥的编程容易让人放弃,兴趣才是最好的老师.无论孩子还是大人,只有发现这件事情真的有趣,我们才会非常执着的去做这件事,比如打游戏.如果编程能像玩游戏一样变得有趣,我相信很多人就特别愿 ...

  8. 为什么从前那些.NET开发者都不写单元测试呢?

    楔子 四年前我虽然也写了很多年代码,由于公司虽然规模不小,却并非一家规范化的软件公司,因此在项目中严格意义上来说并没有架构设计.也不写单元测试,后来有幸加入了一家公司,这家公司虽然也是一家小公司,但是 ...

  9. SPSS输出的结果都要写到文章中吗

    SPSS输出的结果都要写到文章中吗 经常有人问到,SPSS输出的结果都要写到文章中吗?文章中应该写什么呢?比如,均值.中位数.众数.标准差.百分位数.最小值.最大值等等,都要出现在文章中吗?洋洋洒洒那 ...

最新文章

  1. mysql source导入报错ERROR 1366的解决方法
  2. 李飞飞点赞「ARM」:一种让模型快速适应数据变化的元学习方法 | 开源
  3. eclipse 安装svn插件
  4. SDUT OJ[3109] 买买买 背包 dp
  5. excel表中判断A列与B列内容是否相同,相同的话在C列按条件输出!
  6. word2003快速排版工具栏_干货分享 | 闲到在家数瓜子?——先把ID排版秘籍学了吧(上)...
  7. ubuntu上Nginx的配置
  8. FlexyPool如何同时支持连接代理和装饰器
  9. 单细胞转录组基本概念(一)
  10. CodeIgniter中引用某一个表情(smiley)
  11. c语言条件判断!,if条件判断语句,谁能帮我分析一下?
  12. go https 笔记
  13. DB2创建数据库示例
  14. 系统清理软件测试,系统垃圾清理有用吗?六大清理工具评测
  15. 华中师范大学计算机考研论坛,2020年华中师范大学计算机考研经验分享
  16. Failed to compile../public/UEditor/dialogs/template/template.html 1:0Module parse failed: Unexpec
  17. c语言程序设计基本模板,《C语言程序设计基础教程》试讲教案模板
  18. Google 地图- 基本地图类型
  19. 关于网络硬件配置出现问题,无法上网问题的解决
  20. 无人驾驶汽车技术之道路线识别

热门文章

  1. 转android项目开发 工作日志 2011.10.8--onConfigurationChanged屏幕改变事件
  2. DIY敷脸亲身示范做法 - 生活至上,美容至尚!
  3. 5107LiveChatCode
  4. linux c 延迟函数 sleep usleep 使用区别
  5. golang error类型详解
  6. 内核模块相关命令:lsmod,depmod,modprob,modinfo,insmod,rmmod
  7. 对 jiffies 溢出、回绕及 time_after 宏的理解
  8. TCP/IP详解--第二十章
  9. Android开发--用户定位服务--UserLocation
  10. CMake命令之list