到底什么是单元测试
这个问题看似非常简单,单元测试嘛,不就是咱们开发自己写些测试类,来测试自己写的代码逻辑对不对。
这句话没有问题,但是不够准确。
首先我们要明白,这个测试二字前面还有两个字:单元。
它要求我们的测试粒度,小
具体来说就是一个 Test 仅测试一个方法,对这句话的认识非常重要。
市面上常见的错误单测是怎样的呢:
把整个项目启动,开始玩真的调用,入参是数据库里面真的值,所有的操作都落库,一个 Test 从 controller 到 service 再到 dao,一条龙打通。
这种不叫单元测试,这叫集成测试。
如果你现在写的是这样的“单测”,你就会发现,写个测试类不仅要依赖数据库,还要依赖缓存,依赖公司别的团队的服务,亦或是一些三方开放平台的 Http 服务。
当我们的测试类需要依赖太多太多外部因素的时候,只要有一个地方出现问题,你的测试就是 fail 的。
并且入参和出参不能“任你摆布”,你还得想着如何控制别的团队的服务返回你想要的数据。
比如我想测试当依赖的服务 A 返回 sucess 时,我的代码逻辑的正确性,还得想测试服务 A 返回 fail 的逻辑,还想测试它返回 null 的逻辑。
再包括数据库或者缓存的一些返回值的定制,这非常的困难,已经开始劝退人了。
然后把整个项目启动,这通常需要花费数分钟甚至数十分钟的时间,写两个单测一下午过去了,时间都花在调试的启动上了。
所以才会有那么多程序员觉得,单测好难写啊,又耗时,还动不动就 fail,写个 P。
所以回过头来看,到底什么是单测?
单元测试的对象是类中的某个方法,一个 Test 只需要关心这个方法的逻辑正确性,仅仅测试这个方法的逻辑,不应该也不需要关注外部的逻辑。
举个例子,当你写 service 的单测时候,你压根就不应该测试 dao 或者外部服务返回的对不对,这是属于它们的逻辑,跟我 service 没有关系。
可能听着感觉不强烈,我拿代码举个例:

假设我们要测试 trainingYes 这个方法,可以看到方法内部依赖 yesDao 和 OneOneZeroProvicer,一个是数据库,一个是 RPC 服务。
这时候我们的思维应该是:不管传入的 id 在数据库中对应的 yes 数据到底如何,我想让 yesDao 返回 null 的时候它就要返回 null ,想让它不为 null 就不为 null。
对 OneOneZeroProvicer也是一样,我想随意操控让它返回 false 或者 true。
因为数据库和外部服务的逻辑跟我当前的这个 service 方法没关系,我只需要拿到我应该拿到的值来测试我的方法内部的所有逻辑分支即可。
只有这样,我们才能容易的测试到我们所写的代码逻辑。
你想想看,如果你要是测着 trainingYes 还得管着到底哪个 id 能拿到值啊,然后这个 yesDao#getYesById 内部逻辑有没有状态过滤啊,这个 id 对应的数据有被废弃吗,需要关心这个那个,这就非常累了。
再或者你想关心 OneOneZeroProvicer#call怎样才能返回 true,怎样才能返回 false,这就更难了,因为这是别的团队的服务,你连这个服务的代码权限都没,