Jiang-Xuan / blog

个人博客
1 stars 0 forks source link

Jest 中如何 mock 一个依赖模块来测试对于依赖模块的传参是否正确 #12

Open Jiang-Xuan opened 4 years ago

Jiang-Xuan commented 4 years ago

动机

比如下列代码:

// a.js
module.exports = function a() {}

// b.js
module.exports = function b() {}

// ab.js
const a = require('./a')
const b = require('./b')
module.exports = function ab(object) {
  a(object.a)
  b(object.b)
}

你如何测试传递给 ab 的参数 object 中的 a 属性被传递给了 a 模块, b 属性被传递给了 b 模块?

举一个场景

比如有一个系统有一个配置文件, 这个配置文件是 commonjs 格式的, 这个配置文件也可能非常的大, 如果你对这个配置文件的校验放在了同一个函数中, 可能是这样的:

image

第一, 这个函数太复杂, 理解起来很麻烦

第二, 测试用例很难写, 因为你可能需要保持一个合适的配置来测试其他部分,

// ab.js
function ab(object) {
  if (!!object.a === false) {
   throw new Error('缺失 a')
  }
  if (!!object.b === false) {
   throw new Error('缺失 b')

    if (!!object.b.c === false) {
     throw new Error('缺失 b')
    }
  }
}

// ab.test.js
...
// 测试 object.b.c 属性是否存在
test('b', () => {
  const config = { a: 1, b: { c: 3 } }
})

注意这里, 你必须保持 a 是可以通过的, 否则你测试不到 b.c, 函数就会抛出错误, 也就是你无法判断 b 是否能通过测试, 你必须关注 a, 所以拆分进行测试

// a.js
module.exports = function a(a) {}

// b.js
module.exports = function b(b) {}

// ab.js
const a = require('./a')
const b = require('./b')
module.exports = function ab(object) {
  a(object.a)
  b(object.b)
}

这样的拆分测试, 可以分别针对 a, b 写测试

这里 ab 成为了集成函数, 写集成测试来测试这个函数, 只用判断 object.a 被传递给了 a, object.b 被传递给了 b, 也不用测试太多的细节, 导致测试用例太过于复杂

Answer

Jiang-Xuan commented 4 years ago

image

文档 https://jestjs.io/docs/en/jest-object#mock-modules

注意: 当使用 babel-jest 的时候, 调用 jest.mock 将自动提升到代码的顶部. 所以这里可以延迟声明 jest.mock. 如果不使用 babel-jest, 需要手动提升 jest.mock image