我有一个Node.js应用,其中index.js
对于类似Unix和Windows平台的导出不同。
import os from "os";
function throwNotSupportedError() {
throw new Error("Platform not supported.");
}
console.log(os.platform());
switch (os.platform()) {
case "darwin":
case "linux":
module.exports = {
foo: require("./unix/foo"),
bar: require("./unix/bar")
};
break;
case "win32":
module.exports = {
foo: require("./win32/foo"),
bar: require("./win32/bar")
};
break;
default:
throwNotSupportedError();
}
我正在尝试使用如下所示的单元测试来覆盖此文件:
import os from "os";
jest.mock("os");
describe("Linux platform", () => {
test("has `foo` and `bar` methods on Linux platform", () => {
os.platform.mockImplementation(() => "linux");
const app = require("../src");
expect(app.foo).toBeTruthy();
expect(app.bar).toBeTruthy();
});
});
describe("Windows platform", () => {
test("has `foo` and `bar` methods on Windows platform", () => {
os.platform.mockImplementation(() => "win32");
const app = require("../src");
expect(app.foo).toBeTruthy();
expect(app.bar).toBeTruthy();
});
});
问题是os.platform.mockImplementation(() => "win32");
可以工作,但是console.log(os.platform());
仍然显示linux
,即使我在每个测试用例const app = require("../src");
中导入应用程序也是如此。
我的错误在哪里以及如何解决?
答案 0 :(得分:1)
Khang关于jest.resetModules()
的答案指向了正确的方向。我想补充一点,当您重置模块时,对任何过去导入的引用将被“忽略”(重置后会创建一个新实例)。换句话说,重置模块后,将不再使用测试顶部的import os from "os";
。
解决方案
除了jest.resetModules()
外,您还需要重新导入(或在这种情况下需要)要执行的测试中的os
模块。这样,os.platform.mockImplementation(() => "win32");
将应用于模块模拟的最新实例。您的两个测试都需要采用这种结构;
test("has `foo` and `bar` methods on Windows platform", () => {
const os = require('os');
os.platform.mockImplementation(() => "win32");
const app = require("./os-test");
expect(app.foo).toBeTruthy();
expect(app.bar).toBeTruthy();
});
您可能希望使用beforeEach
而不是afterEach
,以确保在测试之前os
模块是干净的。开玩笑应该隔离每个测试文件,但是比后悔更安全?最后,您希望让beforeEach
在所有测试之前运行,而不仅仅是在“ Windows平台” describe
内部。为此,您可以将其移动到文件的根目录,也可以将两个describe
包装在其他describe
中,例如
jest.mock("os");
describe('Platform specific module', () => {
beforeEach(() => {
jest.resetModules();
});
describe("Linux platform", () => {
test("has `foo` and `bar` methods on Linux platform", () => {
const os = require('os');
os.platform.mockImplementation(() => "linux");
...
我希望这会有所帮助!不仅在玩笑中,嘲笑还很棘手。
参考
答案 1 :(得分:0)
您在测试范围内模拟os
模块,但是实际代码在其自己的范围内使用该模块。 jest.mock
仅采用导出的方法并将其替换为jest.fn
,因此,从理论上讲,您的代码需要导出os
,然后您的测试代码仅需要代码一次< / em>在文件顶部。您的测试代码不应直接导入os
。
顺便说一下,从阅读a tutorial on Jest mocks来看,这只是未经检验的理论。
答案 2 :(得分:0)
每次测试后,您需要使用jest.resetModules()
来清除模块缓存:
describe("Windows platform", () => {
afterEach(() => {
jest.resetModules();
})
//...
})