前端测试的反模式 IDCF
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端测试的反模式 IDCF相关的知识,希望对你有一定的参考价值。
参考技术A 在为前端项目编写测试用例的时候,你也许和我一样,曾遇到过以下困扰:因此,才会有人提出前端的测试应尽量去模拟真实的用户行为,Testing-Library就在其官网的“指导原则”章节,鼓励使用者尽量仿照应用真实的使用方式去编写测试,并明确提出,你的测试越接近用户的真实使用方式,它就能给你越多的信心。换句话说,你的测试应该尽量少用函数去手动触发,而要尽量多地利用测试框架给你的API,去模拟Input框的输入,按钮的点击,表单的提交等等。
如此一来,有的函数,你也无需写测试证明它的返回值如你所愿,需要写的,是页面显示了期待的文字,发生了预期的变化,进行了对应的跳转。你会发现,这时的测试就像写在卡里的AC一样。只要测试是通过的,你就有理由相信主体功能没有破坏,而不只是函数工作正常。
看到上面的方案,你可能会立马会想到一些问题。
首先就是测试流程可能会很长,从用户填完表单,点击提交,到期待的变化出现,当中可能经历了好几个函数的执行,连带着一系列的副作用。模拟这一系列行为,似乎是集成测试与E2E测试该干的事情。如果项目中大部分逻辑都是由这种测试去覆盖,看起来与测试金字塔所说的由单元测试作为地基是矛盾的。
我认为,当真实遇到的问题碰到了某种教条规范时,后者该适当地让步。
鼓励多写单元测试的原因在于它们成本低,有针对性。可是在前端项目里面,很多形式上的单元并没有独立的业务含义。
拿React项目举例,好多函数只是因为它们在形式上可以被抽取出来,就被拎到一个单独的文件里,从而降低主函数的复杂度。如果给它写单元测试,你就不得不手动触发它的参数变化,或者检测它的参数函数是否有被调用。
我们写的React hook尤其如此。很多时候抽取自定义的hook是出于逻辑上的原因,把相关的逻辑和数据聚合到一起,减轻UI组件的负担,但这些hook往往没有一个可以轻易解释清楚的业务含义,而且它们也不会被其它地方使用。
所以这类 “单元”只是长得像单元而已,它们其实只是一个实现环节。这里完整的UI操作流程,才更像一个有价值的单元,尽管它们在形式上可能超越了单个函数的范畴。
但我不想矫枉过正,确实有不少情况下,一个util函数,一个hook,一个很小的公共组件,都是有独立存在的价值的,因此,它们也应当被视为真正的单元,确实“有资格”拥有自己的专属测试。
testing-library下面有一个单独的库,叫react-hooks-testing-library,让你无需通过UI行为层面,而是直接以hook的方式去测试它们。它的GitHub页面上,明确提出了使用以及不使用它的场景:当你的hook不与组件强相关,拥有独立含义时可以使用;当你的hook只被一个组件使用,且和它的定义强相关时,则不建议使用。
将上面的规律套用到Angular项目中,也是类似的。对于独立性和通用性不强的pipe,directive,reducer,effect,service,都可以认为它们是实现流程的一部分,从UI行为层面写好测试即可。
总之,在构思前端测试的时候,与其死守“单元测试”的字面含义,不如结合实际场景,重新思考什么才是真正有价值的“单元”,因地制宜地去写。换种角度表述,与其在意我们写的测试是不是“单元测试”,不如追求更核心的东西——我们的测试有没有以合适的方式去校验逻辑。
另外,当我们的“单元”过大,一些逻辑可能就会覆盖不上。像sonar这类工具,不仅会检查你的行数覆盖率,还会检查你的各项条件语句是否有被测试执行。当一套测试的行为流程囊括了多个函数,而且每个函数都有好几个if…else语句时,想要在UI操作与mock数据上把所有情况都覆盖到,成本就会变得非常高昂。
对于此,我们得承认,无论用什么方式组织测试,覆盖所有的条件分支都是不太现实的,而且价值也不大。对于“满足条件A就执行XXX”之类的语句,条件为非A时没有业务上的规定,如果为了刻意覆盖函数的所有条件,就强行测它在非A的情况下返回一个undefined,则没有太多价值。对这类情况,用UI行为测试主要条件即可,如果你实在觉得有重要的逻辑没有被覆盖,不妨回过头来想想,是不是漏掉了某种输入条件,例如特定的用户键入或者特殊的API mock返回值。但是,当有过多的条件分支很难用业务场景去表述和模拟的时候,我们可能需要重新思考代码的实现逻辑是否合理了。
当然,即使按上面这样做,有时候还是会发现要覆盖的条件组合太多,从行为流程上写测试太复杂,这时就不得不做一定的妥协,为那些没有独立性的部分去单独写测试。如果这类测试不太好写,可以参照刚才提到的SWR官方测试用到的技巧,把要测的函数或者是对象放置在一个临时的UI组件下,以最小的成本做UI行为测试。
总结一下上面谈到的几个原则:
以上是关于前端测试的反模式 IDCF的主要内容,如果未能解决你的问题,请参考以下文章