在单元测试中模拟出命名的import



我想为一个使用jsonfile读取数据的模块做一个单元测试。

import * as jsonfile from 'https://deno.land/x/jsonfile/mod.ts'

想模拟jsonfile。readJsonSync返回测试数据,避免写入磁盘。这能做到吗?

希望这个抽象的例子描述了我想要存档的内容:

index.ts

import * as jsonfile from 'https://deno.land/x/jsonfile/mod.ts'
export function readAndReturn() {
return jsonfile.readJsonSync('./example.json')
}

index.test.ts

import { assertEquals } from 'https://deno.land/std@0.112.0/testing/asserts.ts'
import { readAndReturn } from './index.ts'

const dataFixture = {hello: "word"} 
// mock out jsonfile.readJsonSync to return dataFixture and not the actual file content
Deno.test("Reads the data", () => {
assertEquals(readAndReturn(), dataFixture)
})

解决方案非常感谢@mfulton26和@jsejcksn为我指出了正确的方向。

unit.test.importmap.json

{
"imports": {
"https://deno.land/x/jsonfile/mod.ts": "./mocks/jsonfile.ts"
}
}

模拟/jsonfile.ts

import sinon from 'https://cdn.skypack.dev/sinon@11.1.2?dts'
const readJsonSync = sinon.stub()
const writeJsonSync = sinon.stub()
export { readJsonSync, writeJsonSync }

index.test.ts

import { readJsonSync as readJsonSyncMock } from './mocks/jsonfile.ts'
Deno.test(
'Reads the data', () => {
const data = ["hello world"]
readJsonSyncMock.withArgs(`./example.json`).returns(data)
assertEquals(readAndReturn(), data)
}
)
deno test --import-map=unit.test.importmap.json

您可以使用导入映射来替换模块。

只需创建一个包含模拟函数的本地模块./jsonfile.mock.ts,并使用与https://deno.land/x/jsonfile/mod.ts的真实模块相同的名称导出它们。然后,用正确的映射创建一个导入映射,并在运行测试时使用它:

./jsonfile.mock.ts:

export function readJsonSync (filePath: string): unknown {
// implement mocked fn
}
// and any other imports you use from the module

./index.importmap.json:

{
"imports": {
"https://deno.land/x/jsonfile/mod.ts": "./jsonfile.mock.ts"
}
}
deno test --import-map=index.importmap.json index.test.ts

ES模块不能存根。

你可以将你想要存根的功能包装在一个类或对象中,然后导出它,然后你可以使用Sinon.JS或其他库来存根它的方法。

对于在Deno中开始使用Sinon.JS,我建议查看Integration with testing libraries | testing | Manual | Deno,其中引用了一个sinon_example.ts。

用另一个模块包装你的模块在某些情况下可能有效,但如果你的模块有错误的副作用,这将不起作用。

我创建了一个小模块来解决这个问题:Fake Imports.

可能无法模拟静态导入,但是可以模拟动态导入!

使用

import { Importer } from "https://deno.land/x/fake_imports/mod.js";
const importer = new Importer(import.meta.url);
importer.fakeModule("https://deno.land/x/jsonfile/mod.ts", `
function readJsonSync() {}
export {readJsonSync};
`);
// Then load your main module asynchronously
const mainModule = await importer.import("./main.ts");
// And perform your test on mainModule like you usually would

最新更新