从另一个文件模拟一个函数 - Jest

Dal*_*vik 7 javascript unit-testing reactjs jestjs

我正在为我的应用程序编写单元测试用例.有一个函数在Utils部分编写并在所有文件中使用.我想在需要的时候模拟这个Utils功能,但我无法这样做.

这是我的代码设置:

Utils.js

> const getData = (name) => "Hello !!! " + name;
> 
> const getContact = ()=> return Contacts.mobile;
> 
> export {
>     getData,
>     getContact }
Run Code Online (Sandbox Code Playgroud)

Login.js(使用Utils.js)

    const welcomeMessage = (name) => {

    return getData(name);
    }
Run Code Online (Sandbox Code Playgroud)

我的测试文件(Login.spec.js)

import { getData } from '../../src/utils';


jest.mock('getData', () => jest.fn())


describe('User actions', () => {

    it('should get username', () => {
        const value = 'Hello !!! Jest';
        expect(welcomeMessage('Jest')).toEqual(value);
    });

});
Run Code Online (Sandbox Code Playgroud)

当我运行我的测试用例时,我收到此错误:

 Cannot find module 'getData' from 'Login.spec.js'
Run Code Online (Sandbox Code Playgroud)

我试图在官方Jest文档和SO上找到解决方案但是找不到任何东西.我无法修复此错误并模拟此功能.

kar*_*sos 20

jest.spyOn2022年使用失败

我试图使用Sherwin Waters 解决方案jest.spyOn重新创建,但它不起作用。不知道为什么。

更新:现在我知道为什么了。我正在使用 Create-React-App ,在新版本中,他们更改了默认标志,现在默认sourceresetMocks设置为 true 。这就是为什么我们需要在每次测试后对它们进行清理时进行申报。beforeEach

// ./demo/welcomeMessage.js
import { getData } from "./utils"

export const WelcomeMessage = ({name}) => {
    return getData(name)
}

// ./demo/utils.js
const getData = (name) => `Hello ${name}!`;

export { getData }

// ./App.js
import { WelcomeMessage } from "./demo/welcomeMessage";

function App() {
  return (
    <div className="App">
      <h1>My app</h1>
      <p>
        <WelcomeMessage name={'John'} />
      </p>
    </div>
  );
}

export default App;

// ./App.test.js
import { render, screen } from '@testing-library/react';
import App from './App';
import * as utils from "./demo/utils";

jest.spyOn(utils, "getData").mockReturnValue("mocked message");  // this doesn't work as intended

describe('App', () => {
  test('renders header', () => {
    render(<App />);
    expect(screen.getByText(/My app/i)).toBeInTheDocument()
  });

  test('renders correct welcome message', () => {
    render(<App />)
    expect(screen.getByText(/mocked message/i)).toBeInTheDocument()
  });
})
Run Code Online (Sandbox Code Playgroud)

解决方案 #1 使用jest.spyOninbeforeEach

包裹jest.spyOnbeforeEach块状

beforeEach(() => {
  jest.spyOn(utils, "getData").mockReturnValue("mocked message");
});
Run Code Online (Sandbox Code Playgroud)

现在测试应该可以正常工作。这与Stack Overflow 上的帖子类似。

解决方案 #2 使用jest.mock

import * as ...我们可以使用 来模拟我们的模块,而不是使用jest.mock。以下测试工作正常:

import { render, screen } from '@testing-library/react';
import App from './App';

jest.mock('./demo/utils', () => ({
    getData: () => 'mocked message'
}));

describe('App', () => {
  test('renders header', () => {
    render(<App />);
    expect(screen.getByText(/My app/i)).toBeInTheDocument()
  });

  test('renders correct welcome message', () => {
    render(<App />)
    expect(screen.getByText(/mocked message/i)).toBeInTheDocument()
  });
})
Run Code Online (Sandbox Code Playgroud)

如果我们想要有多个模拟实现,例如一个用于测试失败案例,一个用于测试正常案例,那么这种方法就很难使用。我们需要使用doMock异步导入。


Kho*_*hoa 16

第一个参数jest.mock(...)必须是模块路径:

jest.mock('../../src/utils');
Run Code Online (Sandbox Code Playgroud)

因为utils模块是你的代码,而不是第三个lib,所以你必须学习jest的手动模拟:https: //facebook.github.io/jest/docs/en/manual-mocks.html

如果你有这个文件: src/utils.js

你可以通过创建一个文件来模拟它: src/__mocks__/utils.js

此文件的内容是原始文件的复制,但替换实现 getData = jest.fn()

在你的测试文件上,只需调用:jest.mock('../../src/utils');在文件的开头.

那么当你熟悉的时候,你可以在里面调用那个函数beforeEach()并调用它的计数器jest.unmock('../../src/utils');内幕afterEach()

一个简单的思考方式是:

当你打电话时jest.mock('../../src/utils');,这意味着你告诉jest:

嘿如果运行测试符合线路require('../../src/utils'),不要加载它,让负载../../src/__mocks__/utils.


s00*_*433 6

我遇到了同样的问题,最后我找到了解决方案。我把它贴在这里给遇到同样问题的人。

Jest 测试文件:

import * as utils from "./demo/utils";
import { welcomeMessage } from "./demo/login";

// option 1: mocked value
const mockGetData = jest.spyOn(utils, "getData").mockReturnValue("hello");

// option 2: mocked function
const mockGetData = jest.spyOn(utils, "getData").mockImplementation((name) => "Hello !!! " + name);

describe("User actions", () => {
    it("should get username", () => {
        const value = "Hello !!! Jest";
        expect(welcomeMessage("Jest")).toEqual(value);
    });
});
Run Code Online (Sandbox Code Playgroud)

参考资料:https : //jestjs.io/docs/jest-object#jestfnimplementation

jest.spyOn(object, methodName)

创建一个类似于 jest.fn 的模拟函数,但也跟踪对 object[methodName] 的调用。返回一个 Jest 模拟函数。

注意:默认情况下, jest.spyOn 也会调用 spied 方法。这是与大多数其他测试库不同的行为。如果你想覆盖原来的功能,你可以使用:

jest.spyOn(object, methodName).mockImplementation(() => customImplementation)
Run Code Online (Sandbox Code Playgroud)

或者

object[methodName] = jest.fn(() => customImplementation);
Run Code Online (Sandbox Code Playgroud)