[Cli Todo]单元测试

259 阅读1分钟

前言

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

测试流程

  1. 创建__tests__/db.spec.js
  2. 明确目标,我们需要测试fs的读写,因此要进行mock
  3. 创建__mocks__/fs.js
  4. 写测试代码
  5. 运行测试
  6. 大功告成

代码分析

通过jest.mock()fs进行mock

//__tests__/db.spec.js

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

这里使用了describe来测试

//__tests__/db.spec.js

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

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

//__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)
  }
}

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

//__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的操作

//__mocks__/fs.js

fs.clearMocks = () => {
  readMocks = {}
  writeMocks = {}
}
//__tests__/db.spec.js

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

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

后记

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