监视在 Jest 中调用另一个函数的导入函数

Posted

技术标签:

【中文标题】监视在 Jest 中调用另一个函数的导入函数【英文标题】:Spying on an imported function that calls another function in Jest 【发布时间】:2018-11-24 01:14:12 【问题描述】:

我试图监视一个由另一个函数调用的函数,这两个函数都驻留在外部文件中并导入。

Funcs.spec.js:

import * as Funcs from './Funcs'
describe('funcA', () => 
    it('calls funcB', () => 
        jest.spyOn(Funcs, 'funcB')
        Funcs.funcA()
        expect(Funcs.funcB).toHaveBeenCalled()
    

Funcs.js:

export const funcA = () => 
    funcB()

export const funcB = () => 

由于某种原因,间谍在 Funcs.js 的范围内不受尊重。我能做些什么来监视 funcB 以便我知道 funcA 调用了它?

【问题讨论】:

【参考方案1】:

只有方法可以被窥探。如果 funcB 在同一模块中像 funcB() 一样直接调用,则无法监视它。

为了监视或模拟导出的函数,funcAfuncB 应该位于不同的模块中。

这允许在 transpiled ES 模块中监视funcB(模块对象在本机 ESM 中是只读的):

import  funcB  from './b';

export const funcA = () => 
    funcB()

由于模块导入是模块的表示,因此被转译为:

var _b = require('./b');

var funcA = exports.funcA = function funcA() 
    (0, _b.funcB)();
;

funcB 方法与 _b 模块对象绑定在一起,因此可以监视它。

【讨论】:

这是正确的,但不完整。 OP 所要求的(测试在同一文件中导出的功能)可以在不拆分为不同文件/模块的情况下实现。如果您想知道如何查看我的answer。 @a--m 没有拆分成不同的文件/模块 - 这没有被列为要求。代码需要重构以提高可测试性,我只是建议了一种惯用的方法来提高可测试性。这是一个取舍,取决于监视 funcB 的重要性;可能是不必要的。是的,可以使用您建议的 CJS 模块,但 IMO 似乎有点太多了。由于此代码的上下文未知,因此无法保证 CJS 模块在应用程序中是合适的或受支持的(它们也不支持 tree-shaking)。 明白。我同意您关于拆分作为通用规则的测试改进的论点。但由于 OP 声明 它们都驻留在外部文件中并导入这一事实,我认为包括针对此特定要求的解决方案也很重要。事实上,我们在这里讨论的内容也是关于我提到的玩笑问题;)【参考方案2】:

jest issue 引用了您描述的问题。

您的问题的一个可能解决方案(如果您想将函数保留在同一个文件中)是使用 CommonJS,请考虑以下示例:

fns.js

exports.funcA = () => 
  exports.funcB();
;
exports.funcB = () => ;

fns.spec.js

const fns = require("./fns");

describe("funcA", () => 
  it("calls funcB", () => 
    fns.funcB = jest.fn();
    fns.funcA();
    expect(fns.funcB).toBeCalled();
  );
);

【讨论】:

以上是关于监视在 Jest 中调用另一个函数的导入函数的主要内容,如果未能解决你的问题,请参考以下文章

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

无法在 Vue 3 setup() 中监视函数

如何监视调用另一个返回承诺的服务的服务函数 - 打字稿

如何在 Jest 的 globalSetup 函数中使用模块导入 (@) 和 TypeScript?

如何使用 Jest 监视方法调用?

jest.fn() 值必须是模拟函数或 spy 接收函数:[Function getTemplates]