有谁知道我如何在不覆盖所有内容的情况下spyOn
整个类(构造函数和所有方法) (Jest 26.6.3)?
目前,我正在尝试SpyOn (不是模拟)我的运行时,我只想检查它是否被敏捷正确地实例化:
import {
Agile,
Runtime,
} from "../../src";
jest.mock("../../src");
// ..
const RuntimeMock = Runtime as jest.MockedClass<typeof Runtime>;
// ..
const agile = new Agile();
expect(RuntimeMock).toHaveBeenCalledWith(/* ... */)
// ..
但是Runtime的所有属性函数都被Jest覆盖,因此它根本不被实例化。
是否有一种方法可以获得类似于spyOn
方法的行为,但是有一个完整的类,因为我只想检查运行时的构造函数是否在Agile
类expect(RuntimeMock).toHaveBeenCalledWith(/* ... */)
中被正确调用
也许这是我的导入逻辑中的一个问题,因为我从一个模块internal.ts
导入所有类,正因为如此,Jest可能无法正确地重新创建这些类,但我不知道(https://github.com/agile-ts/agile/blob/tests/rewrite-tests/packages/core/src/internal.ts)。
发布于 2022-11-30 17:21:45
这是我的解决办法。最后,我创建了这个代码片段,它可以spyOn整个类,包括它的构造函数。而且使用方法也很简单,您可以将这个片段添加到文件中,并在需要时导入它。
这是代码(类型记录/ES6):
/**
* spyOn references to classes. Use it with spyOnClass
*/
export const classSpy: any = {};
/**
* Utility to Spy On all class methods. Not including the constructor
* @returns a spyOn references to all the class methods
* includes the methods mockClear and mockReset as convenience
* to trigger the respective method for all the spies
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function spyOnClassMethods(proto: any): any {
const properties = Object.getOwnPropertyNames(proto);
const spyHolder: any = {};
for (const i in properties) { spyHolder[properties[i]] = jest.spyOn(proto, properties[i]); }
spyHolder.mockClear = (): void => { for (const i in properties) { spyHolder[properties[i]].mockClear(); } };
spyHolder.mockReset = (): void => { for (const i in properties) { spyHolder[properties[i]].mockReset(); } };
return spyHolder;
}
// To attend jest.mock problems, the should start with 'mock'
const mocksSpyOnClassMethods = spyOnClassMethods;
/**
* Utility to Spy On all class methods and its constructor.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function spyOnClass(mockModuleName: string, mockClassName: string): any {
classSpy[mockClassName] = {};
jest.mock(mockModuleName, () => {
const module = jest.requireActual(mockModuleName) as any;
const mock = {};
classSpy[mockClassName] = mocksSpyOnClassMethods(module[mockClassName].prototype);
mock[mockClassName] = jest.fn().mockImplementation(
(...args: any[]) => {
const instance = new module[mockClassName](...args);
classSpy[mockClassName].constructor = mock[mockClassName];
return instance;
}
);
return { ...module, ...mock };
});
}
用法示例:
import { classSpy, spyOnClass } from './mock-utils';
// This must come before other imports that use ClassName.
spyOnClass('module-name', 'ClassName');
import { ClassName } from 'module-name';
test('this', () => {
doSomethingThatUsesClassName();
expect(classSpy.ClassName.constructor).toHaveBeenCalled();
expect(classSpy.ClassName.someMethod).toHaveBeenCalled();
});
希望它能帮助你和其他人。
https://stackoverflow.com/questions/65070187
复制