随着JavaScript的客户端应用越来越多,开发人员对Nodejs的使用也在不断增加,团队中已经可以使用JavaScript完成对于一个Web Application的前后端全栈开发。与此同时也可以考虑使用JavaScript完成绝大部分的自动化测试,从而可以统一开发团队的技术栈,复用团队的开发人员来开发和维护自动化测试,降低自动化测试的开发和维护成本,并实现JavaScript的敏捷自动化测试。

为了适应这样的开发环境,基于JavaScript的测试框架和工具也随之高速发展,出现了Jasmine,Protractor,Mocha,Selenium,FrisbyJs,Supertest等一批优秀和高效的测试框架和工具,这些工具能够帮团队完成金字塔各层不同类型要求的自动化测试。然而在实际的项目交付开发中,开发和测试人员多多少少会遇到一些痛点想要解决,比如:

  • 客户希望看直观的测试报告,了解测试情况
  • 交付的系统功能不符合客户的需求
  • 每次发布之前都需要花大量的时间做大规模手动回归测试
  • 在做数据库数据迁移的时候,待测数据量太大,分析后怎么保证不影响前端功能
  • API发布频繁,并且每次发布后都需要重新验证所有API
  • 其他团队的人都说自己交付的接口或服务没有问题,我们花了很多时间帮别人找问题
  • 团队内部单个功能都是正确的,但是一集成就发现很多问题
  • 不敢重构,怕影响已有功能
  • 无法理解他人或者自己以前的实现代码
  • 实现过程中,发现业务并不是自己所预想的那样

为了解决以上问题,将借助JavaScript介绍敏捷团队如何选择适合的测试框架,快速、低成本搭建自动化测试框架。

接下来将从测试金字塔的各个层面介绍:

测试金字塔

JavaScript单元测试 与 TDD

TDD的概念和流程

TDD:测试驱动开发(Test Driven Development)

TDD是敏捷开发中的一项核心实践和技术,也是一种设计方法论,在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码,整个过程通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程,通过编写测试用例,先考虑代码的使用需求(包括功能、过程、接口等),而且这个描述是无二义的,可执行验证的。通过编写这部分代码的测试用例,对其功能的分解、使用过程、接口都进行了设计。而且这种从使用角度对代码的设计通常更符合后期开发的需求。可测试的要求,对代码的内聚性的提高和复用都非常有益。

其中更重要的是在使用TDD的思想开发的时候重构方式,也就是TDD = TFD(Test First Development) + Refactoring

整个使用TDD开发的流程(对应下图)概括起来是:

  • 明确当前要完成的功能。可以记录成一个 TODO 列表。
  • 快速完成针对此功能的测试用例编写。
  • 测试代码编译不通过。
  • 编写对应的功能代码。
  • 测试通过。
  • 对代码进行重构,移掉重复的代码,并保证测试通过。
  • 循环完成所有功能的开发。

TDD

单元测试的实践方式与优势

当然,整个过程不会那么顺利,尤其是在一些业务场景复杂的时候,很难保证划分的单元(Unit)足够小。很多团队实践起TDD对整体的开发效率、开发质量并没有显著提高,这时就需要借鉴一些最佳实践来帮助团队更好地完成TDD,提高开发效率。比如以下几点:

  • 测试隔离:编写测试代码时,只考虑测试,不考虑具体内部实现
  • 测试数据选取:选取测试数据尽量模拟现实,越靠近现实越好
  • 独立测试:不同代码的测试应该相互独立
  • 先写断言:编写测试代码时,应该首先编写判断代码功能的断言语句,然后编写必要的辅助语句。
  • 边界条件:充分考虑测试的边界条件
  • 对复杂、核心代码重点测试
  • 利用AOP(beforeEach、afterEach),减少测试代码数量,避免无用功能

有了以上较好的TDD实践,才能更好的体现其在敏捷团队整个交付过程中的优势。如:

  • 测试代码类似文档,更易于理解,特别是复杂场景
  • 写测试的过程中更加理解业务逻辑
  • 小步迭代,集中注意解决一个问题,逐个击破
  • 测试用于验证代码修改,保证没有影响原有的功能
  • 代码质量高,促成良性循环,更有信心的在不断的Refactor中提升代码的质量

单元测试框架

为了保证整个测试过程比较快捷、方便,通常可以使用测试框架组织所有的测试用例和测试代码。那么接下来介绍一些互联网上开源、简单上手的单元测试框架:

Qunit

  • 基于Jquery的测试框架
  • 出来的时间比较久,有很多第三方支持
  • 完整的测试功能
  • 异步测试困难
  • 不需要依赖其它任何软件包或框架
  • 方便跟jQuery等其它框架集成

Jasmine

  • 易于安装,可以使用Jasmine-Node, 也可以使用Grunt 和Jasmine联合使用
  • 异步测试有些复杂
  • 兼容性强
  • 支持Jenkins等CI服务器
  • 支持Unit Testing. API Testing. E2E Testing

Mocha

  • 需要引用Chai,Sinon
  • 测试代码清晰,异步测试方便
  • 支持Jenkins等CI服务器
  • 高扩展性
  • 支持简单异步,包括 promises
  • 支持Unit Testing. API Testing. E2E Testing

以上几种框架各有优缺点,在实际项目对框架选择时可以结合项目实际情况和人员技术栈来进行选择。对于JavaScript测试可以参考如下代码结构,此结构在不同语言和框架使用时差别不大,在此不再赘述。

单元测试代码结构

更多关于JavaScript API测试和JavaScript Web功能测试内容,请参见《基于JavaScript敏捷测试(中篇)》《基于JavaScript敏捷测试(下篇)》