如何模拟每次测试都带有笑话的默认导出对象? [英] how do you mock a default exported object with jest per test?

查看:57
本文介绍了如何模拟每次测试都带有笑话的默认导出对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在测试,需要模拟默认的导出配置对象以测试不同的配置可能性.

I'm currently working on a test where I need to mock a default exported config object to test different configuration possibilities.

我发现可以使用fetch.mock在文件基础上执行此操作,但这并没有给我在每次测试运行中更改模拟的可能性.

I've found a possibility to do this on file basis with fetch.mock but this doesn't give me the possibility to change the mock in each test run.

模拟对象是否有类似jest.mockImplementation的东西,或者它如何工作?

Is there something like jest.mockImplementation for a mocked Object or how does this work?

我用示例代码创建了一个仓库:在这里

I've created a Repo with the example code: here

被测单元:

import * as React from "react";
import config from "./config";

export default function App() {
  return (
    <div className="App">
      {config.greet ? <h1>Hello user</h1> : <h1>Bye user</h1>}
    </div>
  );
}

应该被嘲笑的配置:

const config = { greet: true };

export default config;

我要测试的东西

import App from "./App";
import React from "react";
import { render } from "@testing-library/react";

/* 
I'm currently only able to mock on per file level but not on test level
jest.mock("./config", () => ({
  __esModule: true,
  default: { greet: false },
}));
*/

describe("App", () => {
  it("renders hello if greeting true", () => {
    jest.mock("./config", () => ({
      __esModule: true,
      default: { greet: true },
    }));
    const { debug } = render(<App />);

    // should render 'Hello user'
    debug();
  });

  it("renders bye if greeting false", () => {
    jest.mock("./config", () => ({
      __esModule: true,
      default: { greet: false },
    }));

    const { debug } = render(<App />);

    // should render 'Bye user'
    debug();
  });
});

编辑1

我找到了一种解决方法.如果我在每次测试后都进行resetModules并进行模拟,然后再加载被测单元,则有可能获得不同的值.

I've found a kind of a workaround. If I do resetModules after each test and do the mock and afterwards do the loading of the Unit under test it is possible to get different values.

import React from "react";
import { render } from "@testing-library/react";

describe("App", () => {
  afterEach(() => {
    jest.resetModules();
  });
  it("renders bye if greeting false", () => {
    jest.doMock("./config", () => ({
      __esModule: true,
      default: { greet: false },
    }));

    const App = require("./App");
    const { debug } = render(<App.default />);
    debug();

    // should render Bye user
  });
  it("renders hello if greeting true", async () => {
    jest.doMock("./config", () => ({
      __esModule: true,
      default: { greet: true },
    }));
    // or when using import syntax
    const App = await import("./App");
    const { debug } = render(<App.default />);

    debug();
    // should render Hello user
  });
});

这有效,但是我不喜欢它的语法.您能想到一种解决方案,在其中我将App导入文件的开头并仅覆盖测试中的config对象吗?因为当我渲染多个组件时,我必须在每个测试中再次导入所有与配置相关的组件.这感觉不对.

This works but I don't like the syntax of it. Can you think of a solution where I import App at the beginning of the file and just override the config object in the test? Because when I render more than one component I have to import all config dependant components in each test again. This doesn't feel right.

编辑2

我找到了一种在全局范围内提供可重写模拟的方法.但是我目前还无法调用jest-mock函数.

I found a way to provide a overwritable mock on a global level. But i'm currently stuck getting the jest-mock function invoked.

import React from "react";
import { render } from "@testing-library/react";
jest.mock("./config", () => jest.fn());
import * as config from "./config";
const mockConfig = (config as unknown) as jest.Mock;
import App from "./App";

describe("App", () => {
  it("renders bye if greeting false", async () => {
    mockConfig.mockImplementation(() => ({
      greet: false,
    }));

    const { debug, container } = render(<App />);
    expect(container.querySelector("h1")?.textContent).toBe("Bye user");
    //config is jest.fn()
    debug();
  });

  it("renders bye if greeting true", async () => {
    mockConfig.mockImplementation(() => ({
      greet: true,
    }));

    const { debug, container } = render(<App />);
    expect(container.querySelector("h1")?.textContent).toBe("Hello user");
    //config is jest.fn()
    debug();
  });
});

编辑3

我现在决定提供一个钩子",可以开玩笑地嘲笑它.

I decided for now that I will provide a 'hook' which I can mock with jest.

const config = {
  greet: true,
};

export function useConfig() {
  return config;
}

export default config;

以此,我可以在全局级别为useConfig提供一个自定义的模拟,可以在每个测试调用中覆盖该模拟.

with this, I'm able to provide a custom mock for useConfig on a global level which I can override in each test call.

import React from "react";
import { render } from "@testing-library/react";
import { mocked } from "ts-jest/utils";
jest.mock("./config", () => ({ __esModule: true, useConfig: jest.fn() }));
import * as config from "./config";
const mockConfig = mocked(config);

import App from "./App";

describe("App", () => {
  it("renders bye if greeting false", async () => {
    mockConfig.useConfig.mockReturnValue({
      greet: false,
    });

    const { debug, container } = render(<App />);
    expect(container.querySelector("h1")?.textContent).toBe("Bye user");
    //config is jest.fn()
    debug();
  });

  it("renders bye if greeting true", async () => {
    mockConfig.useConfig.mockReturnValue({
      greet: true,
    });

    const { debug, container } = render(<App />);
    expect(container.querySelector("h1")?.textContent).toBe("Hello user");
    //config is jest.fn()
    debug();
  });
});

由于这导致所有使用该配置的组件的重构,我对此也不满意,并且仍然期待基于对象的模拟解决方案.

Since this leads to a refactoring of all components that use the config I'm not happy with this as well and am still looking forward for a object-based mocking solution.

推荐答案

您可以在配置文件的手动模拟中使用模拟功能,并在执行测试用例之前直接定义其实现,如下所示:

You can rather use a mock function for the manual mock of the config file and define its implementation directly before executing the test case like so:

import React from "react";
import { render } from "@testing-library/react";
import App from "./App";

const mockConfig = jest.fn();

jest.mock("./config", () => mockConfig);

describe("App", () => {
  afterEach(() => {
    jest.resetModules();
  });
  it("renders bye if greeting false", () => {
    mockConfig.mockImplementation(() => ({
      __esModule: true,
      default: { greet: false },
    }));

    import("./App").then((module) => {
      const { debug } = render(<module.default />);
      debug();
    });

    // should render Bye user
  });
  it("renders hello if greeting true", () => {
    mockConfig.mockImplementation(() => ({
      __esModule: true,
      default: { greet: true },
    }));
    import("./App").then((module) => {
      const { debug } = render(<module.default />);

      debug();
    });
    // should render Hello user
  });
});

注意:这里的命名是必不可少的.您必须在常量前面加上'mock'(mockConfig).否则,您将收到一条错误消息,指出变量不在范围内.

Note: The naming is essential here. You have to prefix your constant with 'mock' (mockConfig). Otherwise you will get an Error saying the variable is out-of-scope.

这篇关于如何模拟每次测试都带有笑话的默认导出对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆