说来也惭愧,工作这么多年了,也没听谁在工作中说过单元测试,果然就是程序员的共识吗?最讨厌事就是别人的代码没有注释没有文档,以及让自己去写注释写文档.现在我觉得还要再加一条,讨厌别人不写单元测试,以及让自己去写单元测试.其实也不是完全不知道单元测试,只不过一直以来都没有太当回事.来看看Google对单元测试的解释.好吧,实际上是在Wikipedia里面的.由此可见,单元测试是编程中非常重要的一个环节,或者程序的一个组成部分.不过嘛,都知道代码要写得规范,要有可读性,要遵循设计模式,要遵循代码规范,性能还要高,还要求稳定.但是实际上呢?代码和人,有一个能跑就行,你说是不是嘛.然后再加上制作人,老板的苛刻排期,一个功能自己觉得需要3天,然后都能被领导压到2天,甚至更短,中间还时不时插进来几个其他的bug让你解决.哪儿有那么多理想主义,都是为了生活罢了.不过现实都是生活,网络才是我们程序员的乌托邦.在网络上各种讨论这高性能,扩展性,可读性,优雅的代码,这才是我们精神的寄托.扯远了,抱歉,回到单元测试上来说,以前说起单元测试,唯一的印象就是好像在哪儿看到过这么一个事.就是那个大名鼎鼎的甲骨文,做的Oracle数据库.Oracle数据库那可以非常厉害的,稳定性非常高啊,各方面更是甩开源的MySQL几条街(不是我说的).然后说他们的员工是怎么工作的呢,就是要做一个功能时,先理清楚这个功能相关代码里的那些各种奇奇怪怪的变量到底是干啥的.你要说真的就能完全弄明白才去改,我不是太相信,毕竟那复杂程度,能不能完全搞清楚都不一定,就算搞清楚了也不一定要花多久.反正应该就是差不多弄明白这部分的运行流程逻辑吧.然后就加属于自己的标记变量,应该是类似bool,int这种的用于标识特殊状态的.然后去加各种if-else包裹上自己的逻辑,尽量不让其去污染其他的代码逻辑.改完以后,就去跑单元测试,据说大概全部跑完要一天吧,基本都要跑完测试-根据未通过的测试用例去改代码-改完重新跑测试,就这样估计跑个几次,等全部单元测试都通过了,好了,非常完美,可以提交了.说实话,我都惊呆了,屎山代码真就这么来的吗?等等,我去找找有没有原文.程序员吐槽我永远不会再为 Oracle 工作了 -腾讯云开发者社区-腾讯云反正很多网站都有这样文章,基本内容都非常类似.我也没办法去考证里面说的是不是都是真的.不过作为程序员来看,里面写的东西为真的概率还是挺大的,毕竟只有程序员才最了解程序员.代码能跑就行,别想着去动屎山!,基本最好就是只写自己的代码,新代码的影响范围越小越好,不然身上沾上屎就跑不掉了!不过这篇文章并不是来吐槽这个代码屎山的维护的.而是要在这个例子中看到某些东西的重要性,比如单元测试!为什么代码都屎成这样了,最终还能发布出去正常跑,而且还是在那么大规模用户量的情况下正常运行.靠的就是单元测试!可以这么说,不怕你代码垃圾,也不怕写出来的代码别人看不懂,也不怕你上午写完的代码,一个午觉起来就连自己也看不懂了.只要能够通过完备到极致的单元测试,最终就是优秀可用的代码!所以这就是单元测试的终极意义!帮你兜底.就好比开车的安全带,骑车时的头盔,看起来存在感不强.但是在极端情况下真的能够保命.那为什么以前总是不在意,还不是因为我们自己写出来的绝大部分代码都是不可测试的,极度依赖于上下文,完全没办法单独拿出来测试.而且单元测试这东西不写也不影响运行,写了也看不出来区别.没人愿意去干这个对绩效毫无作用的东西.就拿我的Unity开发框架MyFramework来说(允许我在这里提一下,并非打广告,不然我就把仓库地址放在这里了)抱歉!我没忍住GitHub - ZHOURUIH/MyFramework: Unity 商用级别开发框架,经过了多年经验沉淀.一个在unity上使用的网络游戏客户端开发框架,为unity所有使用方式提供完善的封装和管理,只需要专注于游戏逻辑的编写 · GitHub以前我也不写单元测试,第一次在里面写单元测试是什么时候呢.因为我写了一套自定义的网络传输序列化算法.用于代替protobuf的.比protobuf的带宽要小一些(没实测,只是用AI分析出来的),代价就是通用性,支持的特性上不如protobuf.这是一个按位序列化的算法,采用了很多优化算法,比如 1:上层数据合并,比如定义了4个int字段,但是序列化的时候是当做一个列表来处理的.2:合并长度位,3:预计算符号位,4:压缩无符号整数最高位.等等,所以最终目的就是要尽可能减少序列化完以后的数据长度.这东西麻烦的点在哪儿呢.因为一直都在迭代,所以我没办法保证每次改完以后是完全没有错误的,最早的时候经常就是改了一个地方,在实际运行时一开始还好好的,突然在某个地方就序列化报错了.更可怕的是上下文还不是固定的,不是特定哪个消息报错.这时候就很麻烦了啊.我不可能每次都去打日志调试,去找到出错的数据.非常耗时的.所以就写了一个测试类,专门去写各种情况的序列化,再反序列化.一旦出错就可以直接定位到底是哪儿的问题,也非常容易调试,毕竟条件和数据都是固定了.所以就要把每个数据类型,每个特殊值,各种情况都要写出来进行测试.后来也确实发挥了很大的作用,只要测试通过了,后续真正运行时就不会再有序列化相关的报错了.这是我第一次真正意义去写单元测试,那时候还没有用AI,各种测试条件都是自己手写.从那以后的很长一段时间,我都没有再写其他的测试了.直到AI非常普及以后,以及各种agent大批量出现后,我突然有一天突发奇想,就用workbuddy去试着写单元测试,看看效果如何.然后就一发不可收拾....根本停不下来,可以随意去pushAI帮我写单元测试,哪怕它说已经尽可能地覆盖测试了,依然可以说一句:重新扫描所有代码,找出可测试的代码,补上单元测试.于是现在就是能够达到工具函数97.1%的覆盖率还是挺满意了.至少心里的底气足了很多,敢放心大胆去改这些工具函数了,再也不用担心改出bug了.当然最理想的还是要让所有代码都可测试,不仅仅工具函数,其他的函数也要能够被测试才行.只能说测试覆盖越全面,代码就越可靠.
以前我总是看不起单元测试,不过现在我知道我错了
说来也惭愧,工作这么多年了,也没听谁在工作中说过单元测试,果然就是程序员的共识吗?最讨厌事就是别人的代码没有注释没有文档,以及让自己去写注释写文档.现在我觉得还要再加一条,讨厌别人不写单元测试,以及让自己去写单元测试.其实也不是完全不知道单元测试,只不过一直以来都没有太当回事.来看看Google对单元测试的解释.好吧,实际上是在Wikipedia里面的.由此可见,单元测试是编程中非常重要的一个环节,或者程序的一个组成部分.不过嘛,都知道代码要写得规范,要有可读性,要遵循设计模式,要遵循代码规范,性能还要高,还要求稳定.但是实际上呢?代码和人,有一个能跑就行,你说是不是嘛.然后再加上制作人,老板的苛刻排期,一个功能自己觉得需要3天,然后都能被领导压到2天,甚至更短,中间还时不时插进来几个其他的bug让你解决.哪儿有那么多理想主义,都是为了生活罢了.不过现实都是生活,网络才是我们程序员的乌托邦.在网络上各种讨论这高性能,扩展性,可读性,优雅的代码,这才是我们精神的寄托.扯远了,抱歉,回到单元测试上来说,以前说起单元测试,唯一的印象就是好像在哪儿看到过这么一个事.就是那个大名鼎鼎的甲骨文,做的Oracle数据库.Oracle数据库那可以非常厉害的,稳定性非常高啊,各方面更是甩开源的MySQL几条街(不是我说的).然后说他们的员工是怎么工作的呢,就是要做一个功能时,先理清楚这个功能相关代码里的那些各种奇奇怪怪的变量到底是干啥的.你要说真的就能完全弄明白才去改,我不是太相信,毕竟那复杂程度,能不能完全搞清楚都不一定,就算搞清楚了也不一定要花多久.反正应该就是差不多弄明白这部分的运行流程逻辑吧.然后就加属于自己的标记变量,应该是类似bool,int这种的用于标识特殊状态的.然后去加各种if-else包裹上自己的逻辑,尽量不让其去污染其他的代码逻辑.改完以后,就去跑单元测试,据说大概全部跑完要一天吧,基本都要跑完测试-根据未通过的测试用例去改代码-改完重新跑测试,就这样估计跑个几次,等全部单元测试都通过了,好了,非常完美,可以提交了.说实话,我都惊呆了,屎山代码真就这么来的吗?等等,我去找找有没有原文.程序员吐槽我永远不会再为 Oracle 工作了 -腾讯云开发者社区-腾讯云反正很多网站都有这样文章,基本内容都非常类似.我也没办法去考证里面说的是不是都是真的.不过作为程序员来看,里面写的东西为真的概率还是挺大的,毕竟只有程序员才最了解程序员.代码能跑就行,别想着去动屎山!,基本最好就是只写自己的代码,新代码的影响范围越小越好,不然身上沾上屎就跑不掉了!不过这篇文章并不是来吐槽这个代码屎山的维护的.而是要在这个例子中看到某些东西的重要性,比如单元测试!为什么代码都屎成这样了,最终还能发布出去正常跑,而且还是在那么大规模用户量的情况下正常运行.靠的就是单元测试!可以这么说,不怕你代码垃圾,也不怕写出来的代码别人看不懂,也不怕你上午写完的代码,一个午觉起来就连自己也看不懂了.只要能够通过完备到极致的单元测试,最终就是优秀可用的代码!所以这就是单元测试的终极意义!帮你兜底.就好比开车的安全带,骑车时的头盔,看起来存在感不强.但是在极端情况下真的能够保命.那为什么以前总是不在意,还不是因为我们自己写出来的绝大部分代码都是不可测试的,极度依赖于上下文,完全没办法单独拿出来测试.而且单元测试这东西不写也不影响运行,写了也看不出来区别.没人愿意去干这个对绩效毫无作用的东西.就拿我的Unity开发框架MyFramework来说(允许我在这里提一下,并非打广告,不然我就把仓库地址放在这里了)抱歉!我没忍住GitHub - ZHOURUIH/MyFramework: Unity 商用级别开发框架,经过了多年经验沉淀.一个在unity上使用的网络游戏客户端开发框架,为unity所有使用方式提供完善的封装和管理,只需要专注于游戏逻辑的编写 · GitHub以前我也不写单元测试,第一次在里面写单元测试是什么时候呢.因为我写了一套自定义的网络传输序列化算法.用于代替protobuf的.比protobuf的带宽要小一些(没实测,只是用AI分析出来的),代价就是通用性,支持的特性上不如protobuf.这是一个按位序列化的算法,采用了很多优化算法,比如 1:上层数据合并,比如定义了4个int字段,但是序列化的时候是当做一个列表来处理的.2:合并长度位,3:预计算符号位,4:压缩无符号整数最高位.等等,所以最终目的就是要尽可能减少序列化完以后的数据长度.这东西麻烦的点在哪儿呢.因为一直都在迭代,所以我没办法保证每次改完以后是完全没有错误的,最早的时候经常就是改了一个地方,在实际运行时一开始还好好的,突然在某个地方就序列化报错了.更可怕的是上下文还不是固定的,不是特定哪个消息报错.这时候就很麻烦了啊.我不可能每次都去打日志调试,去找到出错的数据.非常耗时的.所以就写了一个测试类,专门去写各种情况的序列化,再反序列化.一旦出错就可以直接定位到底是哪儿的问题,也非常容易调试,毕竟条件和数据都是固定了.所以就要把每个数据类型,每个特殊值,各种情况都要写出来进行测试.后来也确实发挥了很大的作用,只要测试通过了,后续真正运行时就不会再有序列化相关的报错了.这是我第一次真正意义去写单元测试,那时候还没有用AI,各种测试条件都是自己手写.从那以后的很长一段时间,我都没有再写其他的测试了.直到AI非常普及以后,以及各种agent大批量出现后,我突然有一天突发奇想,就用workbuddy去试着写单元测试,看看效果如何.然后就一发不可收拾....根本停不下来,可以随意去pushAI帮我写单元测试,哪怕它说已经尽可能地覆盖测试了,依然可以说一句:重新扫描所有代码,找出可测试的代码,补上单元测试.于是现在就是能够达到工具函数97.1%的覆盖率还是挺满意了.至少心里的底气足了很多,敢放心大胆去改这些工具函数了,再也不用担心改出bug了.当然最理想的还是要让所有代码都可测试,不仅仅工具函数,其他的函数也要能够被测试才行.只能说测试覆盖越全面,代码就越可靠.