# 前端测试

# 单元测试

单元测试是对软件基本组成单元(软件设计的最小单位)进行正确性检验的测试工作,如函数、过程(function,procedure)或一个类的方法(method)。

常用工具:

  • Jest

# Jest

几个指标

  • %stmts 是语句覆盖率(statement coverage):是不是每个语句都执行了?
  • %Branch 分支覆盖率(branch coverage):是不是每个 if 代码块都执行了?
  • %Funcs 函数覆盖率(function coverage):是不是每个函数都调用了?
  • %Lines 行覆盖率(line coverage):是不是每一行都执行了?

# Snapshot Testing

https://jestjs.io/docs/zh-Hans/snapshot-testing

# 测试覆盖率 coverage

npm run test -- --coverage

使用的 travis.yml

sudo: required
dist: trusty
language: node_js
node_js:
  - '11'
install:
  - npm install -g codecov
  - npm install
script:
  - npm run ci
  - codecov
notifications:
  email: false

# 集成测试:

集成测试是在单元测试的基础上,将所有模块按照概要设计要求组装成为子系统或系统,验证组装后功能以及模块间接口是否正确的测试工作。集成测试也叫组装测试、联合测试、子系统测试或部件测试。

# 其他

  • 通过为前端代码编写单元测试(Unit Test)来测试前端代码
  • Unit Test:一段用于测试一个模块或接口是否能达到预期结果的代码
  • BDD:行为驱动开发 -- 业务需求描述产出产品代码的开发方法
  • TDD:测试驱动开发 -- 单元测试用例代码产出产品代码的开发方法
  • 单元测试框架:
// mocha 示例
describe('Test add', function() {
  it('1 + 2 = 3', function() {
    expect(add(1, 2)).to.be.equal(3);
  });
});

// jest 示例
describe('Test add', function() {
  it('1 + 2 = 3', function() {
    expect(add(1, 2)).toEqual(3);
  });
});

# 测试相关问题

# 对代码进行测试的有什么优缺点?

写作单元测试代码的好处

熟悉单元测试技术,了解相关的基本原理; 掌握代码,积累代码编写经验,积累调试经验,积累分析问题、解决问题的经验; 训练动手能力,单元测试代码不是业务代码,开发、维护过程中不需要特别关注质量要求,底限是达到验证业务代码逻辑性的目的,因而比修改代码要省心、省事; 不需要准备项目运行环境,单元测试代码在运行时的外部依赖比较少,执行验证、调试代码的代价会很低; 降低新手程序员进入项目的门槛,有助于积累信心。

项目过程中写单元测试的好处 一边写代码,一边检查代码中的小错误或者小疏忽,提前解决代码中可能存在的笔误; 为了让单元测试代码更好写,需要花点心思在思考类和方法的结构,好处是可以有效的提升代码的可测试性,否则设计和结构不理想时,单元测试代码写作时也会比较麻烦,需要打很多桩; 在集成测试前,有机会做验证模块内部的逻辑正确性,避免在联调时花费过多的时间来解决小问题,提高联调的效率; 单元测试代码对运行环境依赖小,不需要特别准备复杂的环境,外部模块的行为和表现是可控制的,易于模拟异常场景; 记录已实现的特性,代码即是最好的文档,设计良好的单元测试代码有助于后续维护,降低后期修改引入问题的可能性。

维护或者学习代码过程中写单元测试的好处 熟悉已有代码的逻辑,变量的变化方式,代码的运行轨迹,提高学习代码的效率,降低通过看代码来学习代码的负担; 帮助重构,提高重构的成功率; 辅助问题分析,遇到问题时,可以借助分析单元测试代码来了解模块的一般行为。

单元测试的缺点 单元测试并不万能,并不能解决所有问题,受限于测试范围和场景以及数据,只能满足单模块内部的功能验证的需求; 单元测试覆盖分支,系统测试覆盖场景,二者可能存在重叠,另由于着眼点不同,二者不能相互替代,测试覆盖率有不同的含义; 部分之和不等于整体,单纯追求覆盖率是可笑的,覆盖率只是衡量测试投入的指标,和代码质量并没有直接的关联,另外当覆盖率达到一定程序之后,继续提升覆盖率时投入和产出可能不成正比,效益可能会下降;

同样,单元测试用例数目和代码行之间的比率高也不能说明代码质量一定好; 不能解决或者发现模块可靠性、性能相关、多线程访问相关的问题,这几类问题还是要从设计上分析,编码时注意,单元测试在应对这几类问题前面效果不好; 已有的单元测试代码也需要投入时间和人力来维护,特别是业务变更频繁或者其它原因导致的业务代码频繁变更,同步维护单元测试代码就是一个噩梦; 如果项目需要开发人员写作单元测试,则在项目计划时要充分考虑团队中成员的能力,为单元测试代码开发预留时间,否则美好的愿望最终将无法实现。

# 单元测试编写有哪些原则

为了提高开发人员的代码质量,编写高质量的单元测试,要遵守 3R(Responsible, Reliable, Repeative)原则,具体含义如下:

  • Responsible: 谁开发谁负责测试,在哪里开发就在哪里测试。
  • Reliable: 测试 case 要可靠,并且是值得信赖的,对于底层的任何改动都要能够及时感知。
  • Repeative: 所有单元测试用例都要能够重复运行。能够重复运行就能够进行回归测试、覆盖率统计等等

# 如何做到 Responsible?

开发在完成一个方法,或者一个类之后,就要及时得进行单元测试;不能在对应方法或类的调用处进行测试,比如两个模块 A、B,A 是基础模块,为模块 B 提供服务,那么所有 A 模块的单元测试 case 都应该在 A 模块的内部进行测试。

# 如何做到 Reliable?

为了使得测试用例尽量可靠,就要减少 mock 的使用(对于第三方的调用可以使用 mock),对每层代码的测试都要完全依赖于下层,不能 mock 下层逻辑。因此引入递进集成的概念,比如测试 DAO 时要连接真实的数据库,测试 Service 时要使用真实的 DAO、DB, 测试 Controller 层的代码,要使用真实的 Service、DAO、DB,以此类推。这样就可以最大限度的提高 case 的可靠性。

# 如何做到 Repeative?

必须要做到 case 间完全解耦,没有任何的依赖,这包括和数据库的依赖以及第三方的依赖。case 解耦可以通过准备测试数据、mock 第三方调用来解决。

# 如何进行自动断言?

可以使用 junit 的断言,或者 hamcrest 提供的 assertThat 断言。

# 如何同时使用多个 junit 默认执行类?

比如同时使用@RunWith(DataProviderRunner.class)和@RunWith(SpringJUnit4ClassRunner.class)。 junit 类是不能同时添加多个默认执行类的,此时可以通过编程,将默认执行类所做的工作放在@before 方法来完成。