今天来探讨一下程序员写单元测试这个事儿,为什么国内程序员不喜欢写单元测试呢?我观察下来大概率是下面几个因素相互作用造成的。
1、写了也不给钱
2、没人真正在乎软件质量,尤其当权者更是出问题了抓一抓,到了压项目时间的时候可不会手软。
3、不懂编程也不在乎软件质量的人瞎指挥
4、其实绝大多数程序员也不会写单元测试
既有环境因素也有咱们群体自己的因素,不说别的,我刚上班的时候可不知道咋写单元测试,也没要求我写单元测试,都是后来自己学了,想把代码写优雅点开始试着写写的,后来我进化成了,做新项目时CRUD写写单元测试…因为我怕自己犯SQL写错了或者实体类定义的不对(事实上,经常这样)。
而遇到业务逻辑,说实话时间不允许,大部分自测的时候都是写个简单的接口调用一下自己写的逻辑层方法,看看结果和逻辑层打的日志符不符合预期。。。 我估计我这还算负责的,有的是直接联调或者测试中改问题。
那为什么会这样呢?
简单解释一下。
单元测试并不是你想象的那么简单:
见了:
代码语言:javascript复制int add(int x, int y);
于是你这样写单元测试:
代码语言:javascript复制int unit_test__add() {
assertEQ(add(1,2), 3)
}
事实上,真实的项目中一个函数并不会天然的像上面那个add那么简单、无副作用的。需要设计才行。
举例来说,你负责一个接口叫onNewOrder:
代码语言:javascript复制bool onNewOrder(order Order) {
//一大堆乱七八糟的事
//甚至可能包括更新用户在线状态你敢信?!
}
如果都到了临上线的前一天,order这个数据结构还在变,这个单元测试你写的了吗?
而且,如果它要求你更新用户在线状态、而更新在线状态居然没有抽象出来一个接口,而是要你这个顶层模块自己想办法更新底层模块的数据结构、而那个数据结构甚至都不在本地、同时也天天在变:这个单元测试又该怎么写?
更有甚者:
代码语言:javascript复制//没人知道order应该是个什么样的数据结构,甚至连优惠都需要你自己根据customerID自己查
bool onNewOrder(int orderID, int[] productList, int[] buyNum, int[] price, int customerID)
这玩意儿的单元测试,又该怎么写?最基本的优惠卷要作为实体对象传进来,写单元测试时才能Mock呀。
所以,想要写单元测试,有一个前提条件。那就是先做好设计……
本系统总体分为三层。 最高层是业务层。本层控制订单的确立、支付和交付。 订单是如此定义的;涉及到的优惠卷、vip待遇等规则如此定义,共x类。 流程共分X步、Y个模块,模块接口是xxx、各自的任务是yyy、输出信息是zzz…… 本层总体设计文档由xxx负责,x1、x2、x3协助。各模块设计文档分别由x1、x2、x3负责。 中间层是通讯层。本层负责解决高层各模块之间的通信需求。 报文类型有……定义为……控制流/数据流图如下…… 底层为存储层。本层提供安全可靠、支持分布式事务的业务信息存储能力。 本层接口为……
你看,如果有这个设计,是不是单元测试就很容易写了?
某个模块还没开发完成?本地没有部署?没事,打个桩(stub[1])就好了。
而现实中情况往往是:
- 甲,你负责订单。乙负责数据库。你俩多沟通。
- 啊,介绍一下,这是丙,他负责优惠卷、vip优惠等设计。你俩多和他沟通!
完事你们三个各自闷头写代码。写差不多了一碰头……完蛋,每个人的理解都不一样!
于是你们找经理解决。经理说哎呀你们怎么设计成这样了呢?不是的不是的,客户的需求是这样!
这种情况你敢写单元测试吗,那你自己的设计一天三变,你就得付出成倍的精力才能维护好自己的函数代码以及对应的测试用例,况且上面说的是开发新项目,大部分我们是在更新迭代项目,项目上祖传下来的代码都是一些只闻其名未见过气人的神仙写的,一个函数敢写成千上万行,你怎么单元测试,大部分情况是在这堆屎山里加个自己的if else…..。
你们的项目设计的怎么样,是怎么写单元测试的呢,或者你们技术部门里有没有推过单元测试这个事儿,最后结果怎么样,欢迎评论区说说呀。