Skip to content

Web 前端的单元测试

简单地介绍前端的单元测试,以下内容,大部分来自网络,这次的内容,只是一次归纳而已

单元测试

什么是单元测试?

计算机编程中,单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法

— 维基百科

需要访问数据库的测试不是单元测试

需要访问网络的测试不是单元测试

需要访问文件系统的测试不是单元测试

--- 修改代码的艺术

自动的、可重复的

容易实现

一旦写好,将来都可使用

任何人都可运行

可以快速运行

— 单元测试艺术

单元测试是一段自动化的代码,用来调用被测试的方法或类,而后验证基于该方法或类的逻辑行为的一些假设。单元测试几乎总是用单元测试框架来写的。它是全自动、可信赖、可读性强、可维护的。

— 单元测试艺术

为什么前端要做单元测试

  1. 自动化测试,能保证一定的正确性
  2. 方便重构代码
  3. 容易测试的代码,说明这可能是一个好的设计,或者便于维护和理解
  4. 可以快速验证你的代码的正确性
  5. 写单元测试,相当于写了一份如何使用该代码的说明
  6. 驱动开发(TDD)

开发模式

TDD

TDD(Test-driven development) - 测试驱动开发

我们平时的开发模式是:

  1. 需求分析
  2. 开始开发
  3. 转测
  4. 改 bug
  5. 测试
  6. 上线

TDD 整个流程大概是这样的:

  1. 需求分析
  2. 根据会出现的功能,是方法、类还是组件等,编写相关的测试用例
  3. 快速简单实现功能,使测试用例通过
  4. 对代码进行重构
  5. 测试用例通过
  6. 转测
  7. ….

通过测试驱动开发,有一些优势

  1. 先编写测试用例,其实就是先写出怎么使用该“单元”的事例代码
  2. 然后针对一些边界值、边界情况,尽可能覆盖全面
  3. 根据单元测试运行情况,先快速编写功能代码,达到测试用例都通过为止
  4. 然后开始重构你的代码,使代码更健壮、容易理解上手

多了一层单元测试,对我们的代码是多了一层保障

BDD

BDD(Behavior-driven development) - 行为驱动开发

BDD的核心价值是体现在正确的对系统行为进行设计,所以它并非一种行之有效的测试方法。它强调的是系统最终的实现与用户期望的行为是一致的、验证代码实现是否符合设计目标。但是它本身并不强调对系统功能、性能以及边界值等的健全性做保证,无法像完整的测试一样发现系统的各种问题。但BDD倡导的用简洁的自然语言描述系统行为的理念,可以明确的根据设计产生测试,并保障测试用例的质量。

刘文龙的回答

我也不是很了解 BDD,有兴趣的自己找资料看看~

覆盖率

单元测试代码覆盖率,就是你的测试代码覆盖到功能代码的一个比例

当你的覆盖率很低,那肯定你的测试代码并没有很好测试到某个区域

当你的覆盖率很高或者 100%,证明你的模块所有的代码都是被测试过,但也只是测试过,而不能证明是所有情况都被测试到

所以这个测试覆盖率,我觉得可以当做成一个测试工具,让你清晰得看到哪些代码是没有测试到,而不能当做一个指标

总结

  1. 优点
    1. 保证代码一定的正确性,减少 bug 数
    2. 方便重构、维护
  2. 缺点
    1. 在前期,会需要更多开发时间
    2. 你写的单元测试代码不一定就是好的

讨论

  1. 前端的业务代码,是否需要做单元测试?

如何为 js、vue 搭建、编写单元测试

下面的测试介绍,使用的是 Jest,需要 Mocha 的话自行搜索

搭建环境

JestMocha 配置 Webpack ,自行搜索;现在是用 vue-cli3 的模板配置

什么是单元测试框架和断言库

单元测试框架,就是一个工具,提供一些方法、环境等,方便编写单元测试

断言,就是判断传入的值,是否和预期结果一致,断言库会提供各种各样的断言方法,方便你的测试;例如:断言这个值是否为一个对象、断言两个对象的属性是否一致等

javascript
expect(1).toBe(1) // true
expect(1).toBe('1') // false

Jest

断言

javascript
it('test', async () => {
  expect('123').toBe('123') // true
})

异步测试

回调、promise 等处理,查看官方文档就好了,这里就说下 async/await

javascript
it('test', async () => {
  const data = await func()
  expect(data).toBe(true)
})

这样就行了,无需再做什么处理

测试请求

request 就是后台用的那个方法,nock 是用来模拟请求的

javascript
import { request } from '@packages/commonMethods';
import nock from 'nock';

const requestTemplate = ({ status, data } = {}) => ({
  status: status || 200,
  data: data || {},
  code: '00000000'
});

describe('commonMethods - request', () => {
  const url = 'http://localhost';

  it.only('test', async () => {
    // 模拟
    nock(url)
      .get('/api/test')
      .reply(200, requestTemplate());
    const { code, data } = await request({
      url: url + '/api/test',
      method: 'get'
    });
    expect(code).toBe('00000000'); // true
    expect(data).toMatchObject({}); // true
  });
});

参考资料

  1. Jest 文档
  2. Mocha 文档
  3. Chai 文档
  4. 前端单元测试介绍
  5. nock文档