[TOC] [jest runner]: https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner

前言

jest 是一个 meta 出品的一个测试框架,我们通常用它来做单元测试;在写一些脱离 UI 的功能时,也可以拿他来做 debug 的工具,在减少我们 debug 的工作量的同时还能提高代码质量。

下面我还是用之前那个操作集合的例子来演示,我是如何用 jest 来 debug 的;

PS: 你可能需要先安装jest,和 vscode 的 [jest runner][jest runner]

需求分析

我的需求是假设有任意一个对象的两个新、旧集合,需要计算出他们之间的新增、修改和删除的部分。 $$ \begin{align*} 设:& \ & 新集合为:A,旧集合为:B \ & 要创建的集合:C, 要更新的集合:U, 要删的除集合:D \ 则:& \ & C = A - B \ & D = B - A \ & U = A \cap B \end{align*} $$

实现

根据公式得知,我需要实现差集和交集功能。那我先扩展集合类,并新增差集(Difference)和交集(Intersection)两个方法

index.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
export default class DataSet<T> extends Set<T> {
  Difference = (other: DataSet<T>) => {
    const _difference = new DataSet<T>()
    for (const s of this) {
      if (!other.has(s)) {
        _difference.add(s)
      }
    }
    return _difference
  }

  Intersection = (other: DataSet<T>) => {
    const _intersection = new DataSet<T>()
    for (const s of this) {
      if (other.has(s)) {
        _intersection.add(s)
      }
    }
    return _intersection
  }
}

下面用jest来做测试,新增一个.test文件

index.test.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import DataSet from '.'

describe('data set test', () => {
  it('A - B', () => {
    const A = new DataSet([1, 2]),
      B = new DataSet([2, 3]),
      result = new DataSet([1])
    expect(A.Difference(B)).toEqual(result)
  })
})

其中describe是这组测试的描述,it是每个用例。我们的测试需要写在它们的回调函数时,这个回调函数提供了运行测试的域(scope)。 如果装了vscode [jest runner][jest runner]插件可以在describe和it上方看到run和debug,点击即可运行和debug image1

我们点击run运行它,可以看到控制台有如下输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 PASS  src/util/DataSet/index.test.ts
  data set test
    ✓ A - B (2 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   74.19 |      100 |   66.66 |   74.19 |                   
 index.ts |   74.19 |      100 |   66.66 |   74.19 | 23-30             
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.74 s, estimated 4 s
Ran all test suites matching /\/Users\/furan\/Code\/newBest\/newseed\/robotapp\/src\/util\/DataSet\/index.test.ts/i with tests matching "data set test".

这些输入就是这次测试的成绩单,这些Stmts(语句覆盖)、Branch(判定覆盖率)、Funcs(函数覆盖)、Lines(行覆盖率)是测试的一些指标,Uncovered Line是未覆盖的行。这些指标最好都要达到100。 从Uncovered Line可以看出,代码的22~30行是没执行的。 这是因为我没有测试交集的用例,来完善一下。

index.test.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import DataSet from '.'

describe('data set test', () => {
  it('A - B', () => {
    const A = new DataSet([1, 2]),
      B = new DataSet([2, 3]),
      result = new DataSet([1])
    expect(A.Difference(B)).toEqual(result)
  })

  it('B - A', () => {
    const A = new DataSet([1, 2]),
      B = new DataSet([2, 3]),
      result = new DataSet([3])
    expect(B.Difference(A)).toEqual(result)
  })

  it('A ∩ B', () => {
    const A = new DataSet([1, 2]),
      B = new DataSet([2, 3]),
      result = new DataSet([2])
    expect(A.Intersection(B)).toEqual(result)
  })
})

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 PASS  src/util/DataSet/index.test.ts
  data set test
    ✓ A - B (3 ms)
    ✓ B - A (1 ms)
    ✓ A ∩ B (1 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 index.ts |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        3.322 s, estimated 4 s
Ran all test suites matching /\/Users\/furan\/Code\/newBest\/newseed\/robotapp\/src\/util\/DataSet\/index.test.ts/i with tests matching "data set test".

完善之后再运行就可以看到全部通过了

后话

通过jest我们可以很方便的调试代码,不用把方法绑在UI上,改了还需要热刷新,大大减少了工作量,且用例是可以复用的,在代码改动后,通过单元测试可以快速检验改动的兼容性。可以避免一些改动引起的新bug。

附录

参考资料

测试 - 测试覆盖率

QA

Q: import enum 报错

在 jest.config 中使用 ts-jest

1
2
- // preset: "react-native",
+ preset: "ts-jest",