如何在单个测试的基础上更改模拟实现 [Jestjs] [英] How to change mock implementation on a per single test basis [Jestjs]

查看:23
本文介绍了如何在单个测试的基础上更改模拟实现 [Jestjs]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过扩展默认模拟的行为,在每个单个测试的基础更改模拟依赖项的实现并在下一个测试执行时将其恢复到原始实现.

I'd like to change the implementation of a mocked dependency on a per single test basis by extending the default mock's behaviour and reverting it back to the original implementation when the next test executes.

更简单地说,这就是我想要实现的目标:

More briefly this is what I'm trying to achieve:

  1. 模拟依赖
  2. 在单个测试中更改/扩展模拟实现
  3. 在下一个测试执行时恢复原始模拟
  1. mock dependency
  2. change/extend mock implementation in a single test
  3. revert back to original mock when next test executes

我目前正在使用 Jest v21.

典型的 Jest 测试如下所示:

Here is what a typical Jest test would look like:

__mocks__/myModule.js

const myMockedModule = jest.genMockFromModule('../myModule');

myMockedModule.a = jest.fn(() => true);
myMockedModule.b = jest.fn(() => true);

export default myMockedModule;

__tests__/myTest.js

import myMockedModule from '../myModule';

// Mock myModule
jest.mock('../myModule');

beforeEach(() => {
  jest.clearAllMocks();
});

describe('MyTest', () => {
  it('should test with default mock', () => {
    myMockedModule.a(); // === true
    myMockedModule.b(); // === true
  });

  it('should override myMockedModule.b mock result (and leave the other methods untouched)', () => {
    // Extend change mock
    myMockedModule.a(); // === true
    myMockedModule.b(); // === 'overridden'
    // Restore mock to original implementation with no side effects
  });

  it('should revert back to default myMockedModule mock', () => {
    myMockedModule.a(); // === true
    myMockedModule.b(); // === true
  });
});

这是我迄今为止尝试过的:

Here is what I've tried so far:

优点

  • 在第一次调用后恢复到原始实现

缺点

  • 如果测试多次调用 b 就会中断
  • 在没有调用 b 之前它不会恢复到原始实现(在下一个测试中泄漏)
  • It breaks if the test calls b multiple times
  • It doesn't revert to original implementation until b is not called (leaking out in the next test)

代码:

it('should override myModule.b mock result (and leave the other methods untouched)', () => {

  myMockedModule.b.mockImplementationOnce(() => 'overridden');

  myModule.a(); // === true
  myModule.b(); // === 'overridden'
});

<小时>

2 - jest.doMock(moduleName,工厂,选项)

优点

  • 在每次测试中明确重新模拟

缺点

  • 无法为所有测试定义默认模拟实现
  • 无法扩展默认实现,强制重新声明每个模拟方法

代码:

it('should override myModule.b mock result (and leave the other methods untouched)', () => {

  jest.doMock('../myModule', () => {
    return {
      a: jest.fn(() => true,
      b: jest.fn(() => 'overridden',
    }
  });

  myModule.a(); // === true
  myModule.b(); // === 'overridden'
});

<小时>

3 - 使用 setter 方法手动模拟(如此处所述)

优点

  • 完全控制模拟结果

缺点

  • 大量样板代码
  • 难以长期维持

代码:

__mocks__/myModule.js

const myMockedModule = jest.genMockFromModule('../myModule');

let a = true;
let b = true;

myMockedModule.a = jest.fn(() => a);
myMockedModule.b = jest.fn(() => b);

myMockedModule.__setA = (value) => { a = value };
myMockedModule.__setB = (value) => { b = value };
myMockedModule.__reset = () => {
  a = true;
  b = true;
};
export default myMockedModule;

__tests__/myTest.js

it('should override myModule.b mock result (and leave the other methods untouched)', () => {
  myModule.__setB('overridden');

  myModule.a(); // === true
  myModule.b(); // === 'overridden'

  myModule.__reset();
});

<小时>

4 - jest.spyOn(object, methodName)

缺点

  • 我无法将 mockImplementation 恢复到原始模拟返回值,因此影响了接下来的测试
  • I can't revert back mockImplementation to the original mocked return value, therefore affecting the next tests

代码:

beforeEach(() => {
  jest.clearAllMocks();
  jest.restoreAllMocks();
});

// Mock myModule
jest.mock('../myModule');

it('should override myModule.b mock result (and leave the other methods untouched)', () => {

  const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'overridden');

  myMockedModule.a(); // === true
  myMockedModule.b(); // === 'overridden'

  // How to get back to original mocked value?
});

推荐答案

编写测试的一个很好的模式是创建一个设置工厂函数,该函数返回测试当前模块所需的数据.

A nice pattern for writing tests is to create a setup factory function that returns the data you need for testing the current module.

下面是您的第二个示例之后的一些示例代码,尽管允许以可重用的方式提供默认值和覆盖值.

Below is some sample code following your second example although allows the provision of default and override values in a reusable way.


const spyReturns = returnValue => jest.fn(() => returnValue);

describe("scenario", () => {
  beforeEach(() => {
    jest.resetModules();
  });

  const setup = (mockOverrides) => {
    const mockedFunctions =  {
      a: spyReturns(true),
      b: spyReturns(true),
      ...mockOverrides
    }
    jest.doMock('../myModule', () => mockedFunctions)
    return {
      mockedModule: require('../myModule')
    }
  }

  it("should return true for module a", () => {
    const { mockedModule } = setup();
    expect(mockedModule.a()).toEqual(true)
  });

  it("should return override for module a", () => {
    const EXPECTED_VALUE = "override"
    const { mockedModule } = setup({ a: spyReturns(EXPECTED_VALUE)});
    expect(mockedModule.a()).toEqual(EXPECTED_VALUE)
  });
});

重要的是,您必须重置已使用jest.resetModules() 缓存的模块.这可以在 beforeEach 或类似的拆卸函数中完成.

It's important to say that you must reset modules that have been cached using jest.resetModules(). This can be done in beforeEach or a similar teardown function.

查看 jest 对象文档了解更多信息:https://jestjs.io/docs/jest-object.

See jest object documentation for more info: https://jestjs.io/docs/jest-object.

这篇关于如何在单个测试的基础上更改模拟实现 [Jestjs]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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