单元测试

[Cli Todo]单元测试

前言

折磨一下这个命令行小工具,这里使用的是jest,主要的测试内容是文件的读写能力

测试流程

  1. 创建__tests__/db.spec.js

  2. 明确目标,我们需要测试fs的读写,因此要进行mock

  3. 创建__mocks__/fs.js

  4. 写测试代码

  5. 运行测试

  6. 大功告成

代码分析

通过jest.mock()fs进行mock

1
2
3
4
//__tests__/db.spec.js

const fs = require('fs')
jest.mock('fs')

这里使用了describe来测试

1
2
3
4
5
6
7
//__tests__/db.spec.js

describe('db', () => {
it('can read', () => {})
it('can write', () => {})
})

由于使用到了fake fs,因此我们要准备好假身的功能

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//__mocks__/fs.js

//先将原有的功能全部复制给我们的fake fs
const fs = jest.createMockFromModule('fs')
const _fs = jest.requireActual('fs')

Object.assign(fs, _fs)

//准备测试readFile的功能
let readMocks = {}

fs.setReadFileMock = (path, error, data) => {
readMocks[path] = [error, data]
}

fs.readFile = (path, options, callback) => {
//options是可选参数,如果没有传的话,callback就是第二个参数
if (callback === undefined) callback = options
if (path in readMocks) {
callback(...readMocks[path])
} else {
_fs.readFile(path, options, callback)
}
}

//准备测试writeFile的功能
let writeMocks = {}

fs.setWriteFileMock = (path, fn) => {
writeMocks[path] = fn
}

fs.writeFile = (path, data, options, callback) => {
if (path in writeMocks) {
writeMocks[path](path, data, options, callback)
} else {
_fs.writeFile(path, data, options, callback)
}
}

假身准备完毕,开始写测试的主体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//__tests__/db.spec.js

describe('db', () => {
it('can read', async () => {
const data = [{title: 'hi', done: true}]
fs.setReadFileMock('/testRead', null, JSON.stringify(data))
const list = await db.read('/testRead')
expect(list).toStrictEqual(data)
})
it('can write', async () => {
let fakeFile = ''
fs.setWriteFileMock('/testWrite', (path, data, callback) => {
fakeFile = data
callback(null)
})
const list = [{title: "test1", done: true}, {title: "test2", done: false}]
await db.write(list, '/testWrite')
expect(fakeFile).toBe((JSON.stringify(list) + '\n'))
})
})

为了保障每条测试项都互不干扰,我们需要做一个clear的操作

1
2
3
4
5
6
//__mocks__/fs.js

fs.clearMocks = () => {
readMocks = {}
writeMocks = {}
}
1
2
3
4
5
6
7
8
//__tests__/db.spec.js

describe('db', () => {
afterEach(() => {
fs.clearMocks()
})
...
})

至此测试代码全部写完了。

后记

这是一个简单的单元测试,如果你有意见或建议,欢迎留言告诉我~


单元测试
https://bald3r.wang/2022/08/07/40-Cli-Todo-单元测试/
作者
Allen
发布于
2022年8月7日
许可协议