首页 > 解决方案 > 笑话模拟工厂不适用于模拟类

问题描述

我正在尝试模拟一个服务类来测试一个 React 组件。但是 jest.mock 的模块工厂不起作用。

搜索组件:

import React, { useState } from "react";
import SearchService from "../../services/SearchService";

export default function Search() {
  const [searchResults, setSearchResults] = useState([]);

  function doSearch() {
    const service = new SearchService();
    service.search().then(setSearchResults);
  }

  return (
    <div className="component-container">
      <div>
        <button onClick={doSearch}>search</button>
      </div>
      {searchResults.map((result) => (
        <div key={result}>{result}</div>
      ))}
    </div>
  );
}

搜索服务:

export default class SearchService {
  search = function () {
    return new Promise((resolve) => {
      setTimeout(
        () => resolve(["result 1", "result 2", "result 3", "result 4"]),
        1000
      );
    });
  };
}

测试文件:

import React from "react";
import { screen, render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { act } from "react-dom/test-utils";
import Search from "../features/search/Search";

jest.mock("../services/SearchService", () => {
  return jest.fn().mockImplementation(() => {
    return { search: jest.fn().mockResolvedValue(["mock result"]) };
  });
});

test("Search", async () => {
  render(<Search />);
  const button = screen.getByRole("button");
  expect(button).toBeDefined();
  act(() => {
    userEvent.click(button);
  });
  await screen.findByText("mock result");
});

这与Jest 文档示例的结构相同。在上面的代码中,我通过 jest.mock 的模块工厂参数传递了模拟实现。但它不起作用。当我记录新的 SerchService() 时,我得到“mockConstructor {}”,当我运行测试时,它抛出错误“service.search 不是函数”。

当我将测试文件更改为...

import React from "react";
import { screen, render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { act } from "react-dom/test-utils";
import Search from "../features/search/Search";
import SearchService from "../services/SearchService";

jest.mock("../services/SearchService");

test("Search", async () => {
  SearchService.mockImplementation(() => {
    return { search: jest.fn().mockResolvedValue(["mock result"]) };
  });
  render(<Search />);
  const button = screen.getByRole("button");
  expect(button).toBeDefined();
  act(() => {
    userEvent.click(button);
  });
  await screen.findByText("mock result");
});

它有效......我有点理解为什么它以第二种方式工作,我猜它就像使用 jest.spyOn 一样。我无法理解的是为什么它不适用于第一种方法。

我做错了什么?如何使用 jest.mock 模拟模块实现而不在每个测试中调用 .mockImplementation?

标签: reactjsunit-testingjestjsreact-testing-library

解决方案


我发现文档有问题,工厂需要返回一个函数()(不是箭头函数),所以我将模拟更改为以下内容并且它可以工作:

jest.mock("../services/SearchService.js", () => {
  return function () {
    return { search: jest.fn().mockResolvedValue(["mock result"]) };
  };
});

这篇文章中找到。


推荐阅读