Javscript Jest测试框架:何时模拟模拟?

时间:2020-07-04 12:41:42

标签: javascript testing mocking jestjs

我想为特定测试模拟模块和函数。我有以下内容:

test("my test", () => {
   jest.mock("some_module")
   some_module.some_function = jest.fn();
   ...

})

test("another test", () => {
    ...
});


我的问题是,当测试完成时,两个模拟都将被“取消设置”,以便我可以在下一个测试中使用真正的实现吗?还是我必须自己明确删除所有模拟?

1 个答案:

答案 0 :(得分:2)

测试完成后,所有模拟都将被“取消设置”吗?

Jest测试是在测试文件的基础上进行沙箱测试的,因此通常在该文件中的所有测试运行之后,所有模拟都将被还原。

但是,您在那做什么:some_module.some_function = jest.fn();不是通过Jest的模拟机制进行模拟,而是猴子修补了导入的函数。这将不会被Jest删除。

您应该改为执行以下操作:

import { some_function } from 'some-module-path';

jest.mock('some-module-path');

test('my test', () => {
  ...
  expect(some_function).toHaveBeenCalled(); // e.g.
}

更新:

在评论中进行讨论之后,下面是一个在Jest中安全地进行简单猴子补丁的示例,以便将其还原到同一文件中以供后续测试:

// foo.js -----------------------------------
export const foo = () => 'real foo';


// bar.js -----------------------------------
import { foo } from './foo';

export const bar = () => foo();


// bar.test.js ------------------------------
import { bar } from './bar';
import * as fooModule from './foo';

describe('with mocked foo', () => {
  let originalFoo;

  beforeAll(() => {
    // patch it!
    originalFoo = fooModule.foo;
    fooModule.foo = () => 'mocked foo';
  });

  afterAll(() => {
    // put it back again!
    fooModule.foo = originalFoo;
  });

  test('mocked return value from foo()', () => {
    expect(bar()).toEqual('mocked foo');
  });
});

describe('with real foo', () => {
  test('expect real return value from foo()', () => {
    expect(bar()).toEqual('real foo');
  });
});

更新2:

另一种选择是,您可以模拟依赖项,并通过jest.requireActual临时使用原始实现:

import { bar } from './bar';
import { foo } from './foo';

jest.mock('./foo');
foo.mockReturnValue('mocked foo');
const fooModule = jest.requireActual('./foo')

test('mocked return value from foo()', () => {
  expect(bar()).toEqual('mocked foo');
});

test('real return value from foo()', () => {
  foo.mockImplementation(fooModule.foo);
  expect(bar()).toEqual('real foo');
});