node.js - Jest 模拟打字稿依赖
问题描述
我的 index.ts 文件看起来像这样
import {IS3Client, S3Client} from './client/S3Client';
const s3: IS3Client = new S3Client();
export async function someFunc(event: any, context: any, callback: any) {
const x: string = await s3.getFile('a','b');
}
S3Client.ts 看起来像这样
import * as AWS from 'aws-sdk';
export interface IS3Client {
getFile(bucketName: string, fileName: string): Promise<any>;
}
export class S3Client implements IS3Client {
private s3Client: AWS.S3;
constructor() {
this.s3Client = new AWS.S3();
}
public async getFile(bucketName: string, fileName: string): Promise<any> {
const params = {
Bucket: bucketName,
Key: fileName,
};
return (await this.s3Client.getObject(params).promise()).Body.toString();
}
}
现在我有兴趣模拟 getFile 函数以在测试 index.ts 时返回我想要的
我的测试用例看起来像这样
import {someFunc} from '../src/index';
import { S3Client } from '../src/client/S3Client';
describe("Test Suite", () => {
beforeAll(()=>{
jest.mock('../src/client/S3Client');
const mockedClient: jest.Mocked<S3Client> = new S3Client() as any;
mockedClient.getFile.mockImplementation(() => Promise.resolve('hello'));
});
it("testCase", () => {
const req = {
"key" : ["value"]
};
someFunc(req, null, null);
})
});
我收到以下错误:
TypeError: mockedClient.getFile.mockImplementation is not a function
不知何故,这看起来比我想象的要困难得多。有人可以建议一些东西,提前谢谢?
我添加了另一个这样的类
import { SecretsManager } from 'aws-sdk';
export default class XUtils {
private secretsManager: SecretsManager;
constructor(secretsManager: SecretsManager) {
this.secretsManager = secretsManager;
}
public async getData(urlPrefix: string): Promise<any[]> {
return ['data'];
}
}
我的 index.ts 看起来像这样:
import {IS3Client, S3Client} from './client/S3Client';
import XUtils from './utils/XUtils';
import { SecretsManager } from 'aws-sdk';
const s3: IS3Client = new S3Client();
const secretsManager: SecretsManager = new SecretsManager({ region: process.env.AWS_REGION });
const xUtils: XUtils = new XUtils(secretsManager)
export async function someFunc(event: any, context: any, callback: any) {
const x: string = await s3.getFile('a','b');
const y = await xUtils.getData(x);
}
根据您的建议,我将测试用例修改为如下内容:
import {someFunc} from '../src/index';
import { S3Client } from '../src/client/S3Client';
import XUtils from '../utils/XUtils';
jest.mock('../src/client/S3Client', () => {
const mS3Client = { getFile: jest.fn() };
return { S3Client: jest.fn(() => mS3Client) };
});
jest.mock('../utils/XUtils', () => {
const mXUtils = { getData: jest.fn() };
return { XUtils: jest.fn(() => mXUtils) };
});
describe("Test Suite", () => {
beforeAll(()=>{
mockedClient = new S3Client() as any;
mockedClient.getFile.mockImplementation(() => Promise.resolve('url'));
mockedXUtils = new XUtils(null) as any;
mockedXUtils.getData.mockImplementation(() => Promise.resolve(['data']))
});
it("testCase", () => {
const req = {
"key" : ["value"]
};
someFunc(req, null, null);
})
});
我现在收到错误
TypeError: XUtils_1.default is not a constructor
这个问题到底是什么?
解决方案
- 您不能
jest.mock
在函数范围内使用。它应该在模块范围内使用。 - 您应该在测试用例中使用
async/await
for方法。someFunc
例如
index.ts
:
import { IS3Client, S3Client } from './s3client';
const s3: IS3Client = new S3Client();
export async function someFunc(event: any, context: any, callback: any) {
const x: string = await s3.getFile('a', 'b');
}
s3client.ts
:
import * as AWS from 'aws-sdk';
export interface IS3Client {
getFile(bucketName: string, fileName: string): Promise<any>;
}
export class S3Client implements IS3Client {
private s3Client: AWS.S3;
constructor() {
this.s3Client = new AWS.S3();
}
public async getFile(bucketName: string, fileName: string): Promise<any> {
const params = {
Bucket: bucketName,
Key: fileName,
};
return (await this.s3Client.getObject(params).promise()).Body!.toString();
}
}
index.test.ts
:
import { someFunc } from './';
import { S3Client } from './s3client';
jest.mock('./s3client', () => {
const mS3Client = { getFile: jest.fn() };
return { S3Client: jest.fn(() => mS3Client) };
});
describe('Test Suite', () => {
let mockedClient: jest.Mocked<S3Client>;
beforeAll(() => {
mockedClient = new S3Client() as any;
mockedClient.getFile.mockImplementation(() => Promise.resolve('hello'));
});
it('testCase', async () => {
const req = {
key: ['value'],
};
await someFunc(req, null, null);
expect(mockedClient.getFile).toBeCalledWith('a', 'b');
});
});
覆盖率 100% 的单元测试结果:
PASS stackoverflow/60445082/index.test.ts (8.548s)
Test Suite
✓ testCase (6ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.04s
源代码:https ://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/60445082
推荐阅读
- chef-infra - 使用 Chef infra 客户端卸载软件时 10 分 43 秒后失败
- sas - SAS - 将非数字值放在直方图 sgplot 的 X 轴上
- c# - 带有抽象方法的 C# 枚举
- vector - 如何确保多个语句都返回 Some?
- typescript - 如何从 nuxtjs 打字稿中的 auth 模块(nuxtjs/auth-next)获取 access_token?
- node.js - 如何在 Lightsail 实例中正确设置日志存储/管理?
- azure - CloudBlob.CopyState 在直接帐户到帐户复制完成后为空
- flutter - 在 fcm flutter 中处理通知
- react-native-android - 错误:无法从 E:\test\tryTwo\android\src\pages\tabIcons\tabIconManamement.js 解析模块 ./tabIcons/tab-icon1.png:
- javascript - Nuxt JS 中间件不能使用 axios