HOME/Articles/

JavaScript 基于组件的单元测试

Article Outline

以 React / Vue 为生态圈的前端开发逐渐趋向于组件化,在复杂业务场景中,组件设计能满足复杂需求同时,也能达到一次编写,多处引用的目的。这需要前端团队能够保证组件稳定可靠,在不同环境或项目中有一致行为。那么一定的测试覆盖就有必要。

单元测试的两种类型

组件单元测试分为两种:

  • 针对组件交互和渲染的 UI 测试
  • 针对业务测试

两者不同在于 UI 测试只关注组件内部或其子组件,不依赖外部变量或接口,只关注组件自身,而非业务逻辑,通用性较高。

而业务测试更多与业务关联紧密,需要依赖外部数据,与业务逻辑绑定紧密。例如 API 请求,数据模型变量等等测试。

UI 测试

UI 测试的细分类型如下

  • 快照对比
  • 组件渲染
  • props 传递
  • 回调函数执行
  • 核心交互是否正常

以上几点是对单元测试的要求,若能够在组件开发设计之前思考,单元测试编写能够事半功倍,这并不是强制开发者必须要在组件开发之前先完成测试用例,因为实际上测试编写往往在项目收尾或即将结束时进行,有时候为了保证单元测试的效果,需要重构原有组件的实现,甚至做一些 API 的调整。甚至会有因为提高测试覆盖率而不得已拆解原有比较大的组件代码,这就导致了一些额外的重构工作,这始单元测试看起来美好,实施起来却有些力不从心。

同时也考虑到组件开发过程中面临着需求变更的可能,也会出现刚刚完成单元测试就要重写功能,不得不再重新编写单元测试。这种情况下,开发者需要针对组件类型实行不同测试策略,后面会提到。

这里不去讨论测试设计在哪个阶段或是需求变更是否有价值,也不去强调单元测试有多么必要,而是想讨论单元测试如何能够在提高现有团队迭代效率和组件稳定性之间的平衡,任何的技术方案都需要找到适用场景才能发挥其价值,那么开发者需要作出取舍,到底是何种程度的测试最可行,避免削足适履。

组件划分

之前提到组件类型,是一个比较宽泛的定义,这里根据我个人理解对组件进行分类

  • 基础组件

作为页面或交互的最小元素,只关注基础功能与 UI 布局,只响应数据变化而不参与数据修改操作,其数据变化通过回调函数与父组件通信,把数据维护职责交给父组件(容器组件 / 其他组件),复用性强。

  • 容器组件

容器组件偏向布局样式与数据兼容处理,组装其他组件,通过子组件回调维护自身状态,作为视图与数据的缓冲,适用于某一类业务场景或功能模块。

  • 业务组件 / 高阶组件

业务组件也可以称为高阶组件,与外界依赖较多,不关注 UI ,只负责业务处理,请求 API ,封装组件或容器组件,配置管理和持久化缓存处理。往往与业务绑定比较紧密,或作为一个单独的项目模块而存在。

测试策略

作为基础组件复用性较强的组件类型,因基础组件受需求影响较小,做好核心代码的单元测试,并提高测试覆盖。回调函数,属性传递,和核心 UI 交互都需要有单元测试覆盖。

容器组件可能会因为交互或布局调整有变动,相关交互的测试进可能不依赖与容器组件的结构,例如在定位元素的时候使用绝对定位,而非相对定位,保证测试代码与组件结构解耦。尽可能的降低容器组件的测试覆盖,将基础组件的测试覆盖提高也可以提高容器组件的稳定性。

业务组件可以把业务核心 API 进行测试覆盖,需要适当 mock 数据来完成单元测试,不必关注整体的组件测试覆盖,把重构测试的成本降低。

测试原则

  • 尽可能避免冗余测试用例测试用例需要长期维护,需要精简并且易于他人阅读
  • 保证覆盖前提下,测试用例需要一定弹性尽可能不会因为组件结构微调而造成测试用例重写的情况. 合理利用测试 API

2017-12-22