至此,你应该对如何写单测有点感觉了,我简单总结下上面说的几个小点:
- 单测不应该启动整个项目(包括 Spring 容器),没有这个必要,耗时长
- 单测不应该关心依赖的服务,包括 Dao、provider等其它服务,需要通过 mock 来解耦
- 一个测试方法只测当前要测试的一个类中的一个方法
为什么单测这么难写在对单测有点感觉之后,我们再来盘一盘为什么单测这么难写 。
核心原因在于, 我们本身写的代码不够解耦 。
看到这有人不服了,什么?单测难写还怪我本身写的代码不好,难写是因为本身的业务逻辑复杂!
好吧,这里需要强调一下,逻辑简单的类,其实没必要写单测,一般只是领导要求纯粹的追求覆盖率的时候,才会把这种简单的类补上去 。
举个很简单的例子:
studentService.getStudentById(Long id) ,我相信你都能脑补里面的逻辑,你要说你就想为这样的方法写单测,这当然可以,但是收益不大 。
单测收益最高的就是针对那些复杂的场景,比方说在开发周期比较紧急的时候,核心的、容易出错的逻辑才是更应该去重视的地方(要是开发周期空闲,你要补哪都行)
回到单测难写的问题上,用专业术语来讲,就是 你写的代码可测试性不高 ,导致难以编写对应的单测类 。
怎样的代码是可测试性不高呢?我举个非常简单的例子:
文章插图
假设你要给 garbageMethod 写个单测,是不是有点难?
里面用到了静态方法,又 new 了个service 。
这静态方法我想让返回值等于 111,我只能去研究里面的逻辑 。有人可能想不就是一个方法的逻辑吗,就看看呗 。
那就看看:
文章插图
可能你会说,这两分钟我就看明白了,但是这才一个,要是好多都需要看呢?
你为了测试当前的方法,且花了一堆时间去理解别的不需要测试的类的逻辑,这做法本身就不符合逻辑 。
然后那个 noSevice 是 new 的,这如何控制它的返回值啊?我想 mock 这个类也替换不了啊!
所以,这样的代码就是可测试性低的代码,不好 mock (当然,mock 框架支持静态方法的 mock,不过new noSevice 不好弄,当然一般人都有不会这样写的,我只是为了举例)
还有各种类之间有继承关系的,这种测试难度都比较大 。
就是上面的种种原因,导致我们的单测难以编写 。
所以如果我们在设计接口的时候,先编写单测,我们写出来的代码其实可测试性就很高了,因为你完全晓得这样的写法会使得你单测很难进行下去,自然而然你写的代码就会往解耦的方向发展(比如上面的 noService 肯定会注入) 。
我来列举下具体哪几种代码写法使得我们单测难以编写:
- 静态方法(不好mock替换注入,不过现在mock框架已支持)
- 内部直接 new,强依赖,无法 mock 替换注入
- 继承类,测试当前类的方法逻辑,还需要关心父类逻辑和mock父类的服务(所以我们常说组合优于继承)
- 全局变量,这个应该好理解,好方法都公用,你改了值之后,会影响别的测试类,特别是并发执行测试类时,就傻了
- 时间等一些未决行为,代码里面有 new Date,逻辑是近 15 天可行,然后超过 15 天就跑不通了(当然可以通过动态计算时间)
写个单测例子说了那么多,不如实战一下,我就拿 trainingYes 来举例说明,这里引入 mockito 测试框架 。
可以看到,通过注解 mock 了需要 mock 的 dao 和 provider,然后将其注入到我们要测试的 yesService 中 。
文章插图
接下来就是具体的逻辑,根据场景我一共写了 4 个方法来测试:
推荐阅读
- 博物馆|新人在收藏钱币时,需要注意哪些坑?该如何避免?
- 暗黄没气血的女人真该补补了
- |我一直钓“跑铅”,该钓法有何利弊?
- 滑雪过程中足踝或手腕扭伤了应该怎么做?
- 揭秘赵云死亡真相 赵云是怎么死的
- 薪酬|我那么拼命干啥,也不得到该有的成绩
- 10W左右预算到底该买个啥车? 10万左右买什么车好
- 正史中岳飞是因为什么罪名被处死的? 历史上岳飞怎么死的
- 华为|华为新旗舰耳机FreeBuds Pro 2亮相!首发搭载超感知原声双单元
- 甘罗是怎么死的?