typescript - 如何使用 jest 模拟返回函数的函数
问题描述
我正在尝试模拟返回另一个函数的函数。但是,我不确定如何使用 jest 来完成这项工作。提前致谢。
- 应该成功返回。
- 应该抛出一个错误。
需要模拟的模块:
const initGreeter = () =>{
return {
sayHello: (name:string) =>{
console.log(`Hello: ${name}`)
}
}
}
export default initGreeter;
被测模块:
import initGreeter from './greeter';
export const greetSomeone = (name:string) =>{
const greeter = initGreeter();
greeter.sayHello(name)
}
测试:
import initGreeter from '../../utils/greeter';
import { greetSomeone } from '../../utils/greeterConsumer';
describe('greeterConsumer', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('greeter consumer should call SayHello on greeter', () => {
//TODO:mock greeter here
greetSomeone('sam');
expect(greeter.sayHello.mock.call[0][0]).toBe('sam');
});
it('greeter consumer throws exception', () => {
//TODO:mock greeter here so it throws exception
expect(greetSomeone('sam')).toThrow(Error);
});
});
请注意,更新 1 和 2 中的代码是 @slideshowp2 解决方案中代码的延续。
更新 2:看起来如果更改下面的代码
jest.mock('./greeter', () => {
return jest.fn(() => mGreeter);
});
至
jest.mock('../../utils/greeter.ts', () => ({
__esModule: true,
default: jest.fn(() => mGreeter)
}));
有用。
还有其他方法可以使 @slideshowp2 中的代码按原样工作,例如在 tsconfig 中设置 "esModuleInterop": true 。但是,我不完全理解为什么它适用于任何一种情况。我可能会在未来检查并在这里更新。
更新 1:从@slideshowp2 实施解决方案后
我在测试中收到以下错误
失败 src/测试/utils/greeterConsumer.test.ts ● greeterConsumer › greeter 消费者应该在 greeter 上调用 SayHello
TypeError: greeter_1.default is not a function
2 |
3 | export const greetSomeone = (name:string) =>{
> 4 | const greeter = initGreeter();
| ^
5 | greeter.sayHello(name)
6 | }
at Object.<anonymous>.exports.greetSomeone (src/utils/greeterConsumer.ts:4:21)
at Object.<anonymous> (src/__tests__/utils/greeterConsumer.test.ts:18:5)
解决方案
您可以使用jest.mock(moduleName, factory, options)手动模拟../../utils/greeter
模块。
例如
greeter.ts
:
const initGreeter = () => {
return {
sayHello: (name: string) => {
console.log(`Hello: ${name}`);
},
};
};
export default initGreeter;
greeterConsumer.ts
:
import initGreeter from './greeter';
export const greetSomeone = (name: string) => {
const greeter = initGreeter();
greeter.sayHello(name);
};
greeterConsumer.test.ts
:
import initGreeter from './greeter';
import { greetSomeone } from './greeterConsumer';
const mGreeter = {
sayHello: jest.fn(),
};
jest.mock('./greeter', () => {
return jest.fn(() => mGreeter);
});
describe('greeterConsumer', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('greeter consumer should call SayHello on greeter', () => {
greetSomeone('sam');
expect(initGreeter).toBeCalledTimes(1);
expect(mGreeter.sayHello).toBeCalledWith('sam');
});
it('greeter consumer throws exception', () => {
mGreeter.sayHello.mockImplementationOnce(() => {
throw new Error('oops');
});
expect(() => greetSomeone('sam')).toThrowError('oops');
expect(initGreeter).toBeCalledTimes(1);
expect(mGreeter.sayHello).toBeCalledWith('sam');
});
});
单元测试结果:
PASS examples/65281989/greeterConsumer.test.ts
greeterConsumer
✓ greeter consumer should call SayHello on greeter (3 ms)
✓ greeter consumer throws exception (10 ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
greeterConsumer.ts | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.473 s
源代码:https ://github.com/mrdulin/jest-v26-codelab/tree/main/examples/65281989
推荐阅读
- python - 如何解决 django 中的 UnicodeDecode 错误
- c - 如何在 Tizen Native 中从手表打印心率和步数数据?
- hybris - 如何为 Hybris 2011 版本创建示例扩展
- c# - HttpServiceFactory 接口中的方法太多
- google-chrome - SameSite 无 cookie 未与跨源 IFrame 请求一起发送
- python - QTableWidget中如何显示选择效果QLineEdit
- dbup - DbUp - 不同变量值的循环脚本
- ruby - 捆绑器无法安装
- android - 带有子视图的 CustomView 不能正确计算 recyclerview 子视图的高度
- php - 添加数据时,数据库表会混淆