【问题标题】:Python like function mock in JavaScript类似 Python 的 JavaScript 中的函数模拟
【发布时间】:2019-02-04 10:05:49
【问题描述】:

使用Python 可以很容易地模拟在被测函数中使用的函数。

# my_module.py
def function_a():
    return 'a'


def function_b():
    return function_a() + 'b'



# tests/test_my_module.py
from unittest import TestCase
from unittest.mock import patch

from my_module import function_b


class MyModuleTestCase(TestCase):
    @patch('my_module.function_a')
    def test_function_b(self, mock_function_a):
        mock_function_a.return_value = 'c'

        self.assertEqual(function_b(), 'cb')

JavaScript 中是否可以使用例如jest 进行类似的操作?

# myModule.js
function myFunctionA() {
  return 'a';
}

export function myFunctionB() {
  return myFunctionA() + 'b';
}



# __test__/test.myModule.js
import { myFunctionB } from '../myModule';

describe('myModule tests', () => {
  test('myFunctionB works', () => {
    // Mock `myFunctionA` return value here somehow. 
    expect(myFunctionB()).toBe('cb')
  });
});

我已经阅读了https://github.com/facebook/jest/issues/936,但仍然不知道该怎么做,因为有很多(hacky)建议(其中一些大约 2 岁)。

【问题讨论】:

    标签: javascript python testing mocking jestjs


    【解决方案1】:

    Jest 可以使用jest.mock() 模拟整个模块或使用jest.spyOn() 结合mockImplementation() 等函数模拟单个模块导出。

    这使得模拟从库中导入的函数变得容易:

    // ---- lib.js ----
    export function myFunctionA() {
      return 'a';
    }
    
    
    // ---- myModule.js ----
    import { myFunctionA } from './lib';
    
    export function myFunctionB() {
      return myFunctionA() + 'b';  // call lib.myFunctionA()
    }
    
    
    // ---- myModule.test.js ----
    import { myFunctionB } from './myModule';
    import * as lib from './lib';
    
    describe('myModule tests', () => {
      test('myFunctionB works', () => {
        const mock = jest.spyOn(lib, 'myFunctionA');  // create a spy on lib.myFunctionA()
        mock.mockImplementation(() => 'c');  // replace the implementation
    
        expect(myFunctionB()).toBe('cb');
    
        mock.mockRestore();  // remove the spy and mock implementation
      });
    });
    

    在问题myModule 的代码示例中包含两个函数,一个直接调用另一个。

    因为模拟适用于整个模块或模块导出,所以模拟从myFunctionB() 中直接调用myFunctionA() 的代码编写方式将非常困难。

    我发现解决此类情况的最简单方法是将模块导入自身并在调用函数时使用该模块。这样,它就是被调用的模块导出,它可以在测试中被模拟:

    // ---- myModule.js ----
    import * as myModule from './myModule';
    
    export function myFunctionA() {
      return 'a';
    }
    
    export function myFunctionB() {
      return myModule.myFunctionA() + 'b';  // call myModule.myFunctionA()
    }
    
    
    // ---- myModule.test.js ----
    import * as myModule from './myModule';
    
    describe('myModule tests', () => {
      test('myFunctionB works', () => {
        const mock = jest.spyOn(myModule, 'myFunctionA');  // create a spy on myModule.myFunctionA()
        mock.mockImplementation(() => 'c');  // replace the implementation
    
        expect(myModule.myFunctionB()).toBe('cb');
    
        mock.mockRestore();  // remove the spy and mock implementation
      });
    });
    

    【讨论】:

    • 谢谢!我一直在寻找这个答案太久了!
    • @wei 真棒,很高兴听到它有帮助!
    • 不幸的是,它不如 python 的 mock.patch 强大:|有了它,可以模拟任何模块可访问的任何属性(内置对象的属性除外,Python 不擅长,但这些通常不是问题,因为您通常可以模拟整个内置对象)。感谢您的回答,很有帮助!
    猜你喜欢
    • 2012-01-06
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多