如何处理模块和打字稿类型的笑话模拟功能

Posted

技术标签:

【中文标题】如何处理模块和打字稿类型的笑话模拟功能【英文标题】:how to deal with jest mock function of a module and typescript type 【发布时间】:2017-12-10 00:51:23 【问题描述】:

我使用ts-jestjest 用打字稿编写我的测试文件。

我很困惑如何输入模块的模拟函数。

这是我的代码:

./module.ts:

import IObj from '../interfaces';

const obj: IObj = 
  getMessage() 
    return `Her name is $this.genName(), age is $this.getAge()`;
  ,

  genName() 
    return 'novaline';
  ,

  getAge() 
    return 26;
  
;

export default obj;

./module.test.ts:

import * as m from './module';

describe('mock function test suites', () => 

  it('t-1', () => 
    // I think the jest.Mock<string> type here is not correct.
    m.genName: jest.Mock<string> = jest.fn(() => 'emilie'); 
    expect(jest.isMockFunction(m.genName)).toBeTruthy();
    expect(m.genName()).toBe('emilie');
    expect(m.getMessage()).toEqual('Her name is emilie, age is 26');
    expect(m.genName).toHaveBeenCalled(); 

  );

);

如何输入模块m的模拟函数genName

typescript在这里给我一个错误:

错误:(8, 7) TS2540: 无法分配给“genName”,因为它是常量或只读属性。

【问题讨论】:

【参考方案1】:

您想模拟模块,然后更改其中的导出函数。这应该替换您的导入语句。

jest.mock('./module', () => (
    genName: jest.fn().mockImplementation(() => 'emilie')
))

【讨论】:

这不起作用,因为 genName 的范围仅限于该块,并且在整个文件中不可用 我在整个代码中都在使用它,所以它确实有效。如果您需要测试是否调用了 genName(或类似的东西),您可以将 jest.fn() 分配给块外部的 mock* 变量并引用它:genName: mockGenName 然后 expect(mockGenName).toHaveBeenCalled() 或其他。跨度> @trevorgk 建议的解决方案工作正常。我只想强调您可能想要更改特定测试的实现:it('returns franc', () =&gt; m.genName.mockImplementationOnce(() =&gt; 'franc') ) @phillyslick 感谢您的解决方案,但在这种情况下,您如何测试功能本身?喜欢:expect(genName()).toReturnSomething...?【参考方案2】:
import * as m from './module'

jest.mock('./module', () => (
    genName: jest.fn().mockImplementation(() => 'emilie')
    // will return "enilie" for all tests
))

it('returns franc', () => 
  m.genName.mockImplementationOnce(() => 'franc')
  // will return "franc" for this particular test
)

【讨论】:

第二个 mockImple 不起作用我得到 Property 'mockImplementation' does not exist on type '() => Promise'。【参考方案3】:

我在嘲笑它:

jest.mock('./module')
const genName = require('./module')

在我的测试中:

 genName.mockImplementationOnce(() => 'franc')

非常适合我,没有打字错误

【讨论】:

如果能解释你的答案就太好了【参考方案4】:

这就是我解决相同问题的方法,也是我现在进行所有嘲笑和监视的方法。

import * as m from './module';

describe('your test', () => 
  let mockGenName;

  beforeEach(() => 
    mockGenName = jest.spyOn(m, 
      'genName').mockImplemetation(() => 'franc');
  )

  afterEach(() => 
    mockGenName.mockRestore();
  )


  test('your test description', () => 
    // do something that calls the genName function
    expect(mockGenName).toHaveBeenCalledTimes(1);
  )

)

使用此设置,您可以以编程方式更改不同测试的模拟实现,然后断言该函数已被调用以及它被调用的内容,同时在测试之间和所有测试之后清除模拟。

【讨论】:

我得到 TypeError: jest.spyOn(...).mockImplemetation is not a function @ykonda 我修正了拼写错误【参考方案5】:

我得到错误的原因是:

模块对象 foo 的属性(import * as foo from 'foo')类似于冻结对象的属性。

欲了解更多信息,请参阅In ES6, imports are live read-only views on exported values

当我将import * as m from './module' 更改为import m from './module'; 时,错误消失了。

软件包版本:

"typescript": "^3.6.4"
"ts-jest": "^24.1.0"
"jest": "^24.9.0",

jest.config.js:

module.exports = 
  preset: 'ts-jest/presets/js-with-ts',
  //...

tsconfig.json:

"compilerOptions": 
    "target": "es6",
    "module": "commonjs",
    //...

【讨论】:

【参考方案6】:

试试这个 - https://jestjs.io/docs/mock-function-api#typescript

简而言之,只有三种可能的策略

    模拟要导入的整个模块并获取模拟函数的处理程序以对其进行操作(jest.Mock()、jest.MockedFunction) 模拟部分导入的模块并获取模拟函数的处理程序以对其进行操作(jest.Mock() with factory, jest.MockedFunction) 按原样导入模块,然后监视需要模拟的函数 (jest.spy())

【讨论】:

以上是关于如何处理模块和打字稿类型的笑话模拟功能的主要内容,如果未能解决你的问题,请参考以下文章

使用打字稿时如何处理快速控制器方法参数?

在笑话和打字稿中模拟交叉点观察者

使用笑话模拟时的打字稿错误

具有基于变量的标签值的打字稿匿名对象

Visual Studio Code 中的打字稿是不是有自动导入功能?

打字稿。为啥功能接口中描述的“返回值”类型没有严格执行?