代码之家  ›  专栏  ›  技术社区  ›  rel1x

在Jest中重置节点模块

  •  0
  • rel1x  · 技术社区  · 5 年前

    我有一个节点。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 回复  |  直到 5 年前
        1
  •  2
  •   Arnaud Valle    4 年前

    康的回答 jest.resetModules() 指向正确的方向。我想补充一点,当你重置模块时,对任何过去导入的引用都将被“忽略”(重置后会创建一个新实例)。换句话说 import os from "os"; 在模块重置后,测试的顶部将不再使用。

    解决方案

    除了 开玩笑重置模块() 您需要重新导入(或在本例中重新要求) 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 ,以确保 操作系统 测试前,模块是干净的。Jest应该隔离每个测试文件,但安全总比抱歉好?最后,你会想要 之前 在所有测试之前运行,而不仅仅是在“Windows平台”内 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");
          ...
    

    我希望这有帮助!嘲弄往往很棘手,而不仅仅是开玩笑。

    工具书类

        2
  •  0
  •   HenryTK    5 年前

    你在嘲笑 os 模块在您的测试范围内,但您的实际代码在自己的范围内使用该模块。 jest.mock 只接受导出的方法并将其替换为 jest.fn 因此,理论上,您的代码需要导出 操作系统 ,那么您的测试代码应该只需要您的代码 一旦 在文件的顶部。您的测试代码不应导入 操作系统 直接地

    顺便说一句,这只是从阅读中得出的未经检验的理论 a tutorial on Jest mocks .

        3
  •  0
  •   kkkkkkk    5 年前

    你需要使用 jest.resetModules() 每次测试后,清除模块缓存:

    describe("Windows platform", () => {
        afterEach(() => {
            jest.resetModules();
        })
    
        //...
    })