2017-09-09 12:50:12

Node: 善用require优化集成测试

单元测试测函数,集成测试测模块

背景

在集成测试中,有一些很麻烦的模块是很影响测试的,比如说API调用和SOA调用,通常可以用如下的办法将它们假造一部分:

// a.js
exports.soa = () => {/* */}

// test.js
const cache = require('./a')
cache.soa = () => console.log('mock !!!')

只需要在运行逻辑代码前调用上面两句,就可以让我们伪造的代码替代原始函数了。

exports.soa这种形式可以通过require('./a').soa来赋值,然而集成测试是测的模块,更多的场景是需要假造module.exports,即要求require('./a')拿到的就是我们自己定义的函数,这个时候上面的办法就行不通了,这就需要灵活运用require的API了。

require API

大部分Node用户都不会用到require的静态函数或静态属性,然而其实它们是十分有用处的,这里简单介绍和本文有关的两个

require.resolve

require('./a.js')函数内部会调用require.resolve方法,来将./a.js解析为绝对路径,如果该路径下文件不存在,则直接抛错。

配合try{}catch(){},它可以用来完美替代require('glob').syncpath.resolve这一个动态加载模块的组合。

require.cache

Object.keys(require.cache)会返回已导入模块的绝对路径的数组,其实require.cache[key]的值就是在Node文件内拿到的module对象了,通过更改require.cache[key].exports即可达到动态更改module.exports的值这样的目的

范例

cosnt path = './a.js'
const key = require.resolve(path)
require(path)
require.cache(key).exports = () => console.log('自定义函数')

其他

require的源码印象中也就一两百行,是CommonJS在Node中的精华体现,读者有时间完全可以抽三四分钟仔细看一看。

另外,require其实还有一个静态属性:

require.extensions

require.extensions['.mjs'] = require.extensions['.js'];

如上的语句就是将.js后缀文件的解析函数移植到.mjs后缀的文件上,被用来解析非内置支持的文件类型。实际上,Object.keys(require.extensions)返回的是['.js', '.json', '.node'],内置支持的文件类型只有这三种。require()内部也是使用它来解析对应的文件内容的。

虽然require.extensions早在v0.10就被标记为deprecated,但是到现在v8了都没有被删除,因此还是可以利用它来做点有趣的事情的。

本文链接:https://smallpath.me/post/node-require-intergration-test

-- EOF --