javascript - 如何在单个测试的基础上更改模拟实现?

标签 javascript jestjs

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

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

  1. 模拟依赖
  2. 在单个测试中更改/扩展模拟实现
  3. 在下一次测试执行时恢复到原始模拟

我目前正在使用 Jest v21。典型测试如下所示:

// __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
  });
});

到目前为止,这是我尝试过的:

  1. mockFn.mockImplementationOnce(fn)

    it('should override myModule.b mock result (and leave the other methods untouched)', () => {
    
      myMockedModule.b.mockImplementationOnce(() => 'overridden');
    
      myModule.a(); // === true
      myModule.b(); // === 'overridden'
    });
    

    优点

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

    缺点

    • 如果测试多次调用 b 就会中断
    • 直到 b 没有被调用(在下一次测试中泄漏),它才会恢复到原来的实现
  2. jest.doMock(moduleName, factory, options)

    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 方法手动模拟(如 here 所述)

    // __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)

    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?
    });
    

    缺点

    • 我无法将 mockImplementation 还原为原始的模拟返回值,因此会影响下一次测试

最佳答案

使用mockFn.mockImplementation(fn) .

import { funcToMock } from './somewhere';
jest.mock('./somewhere');

beforeEach(() => {
  funcToMock.mockImplementation(() => { /* default implementation */ });
  // (funcToMock as jest.Mock)... in TS
});

test('case that needs a different implementation of funcToMock', () => {
  funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
  // (funcToMock as jest.Mock)... in TS

  // ...
});

关于javascript - 如何在单个测试的基础上更改模拟实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48790927/

相关文章:

javascript - 如何确定 JEST 是否正在运行代码?

javascript - 检查输入值是否有 "."(点)(Javascript)

javascript - Chrome 扩展浏览器操作事件未触发

javascript - 如何仅过滤数组中符号类型的值?

javascript - Jest - 嵌套 promise 断言永远不会返回

typescript - 如何让 Jest 覆盖仅限导出线路?

vue.js - 如何使用 jest 测试 Vue.js 组件中方法的错误

javascript - 两个具有 keyup 功能的输入字段

javascript - 防止圆圈重叠

javascript - 使 Scrollbar Angular JS 和 Framework 7 移动