为什么在 运行 读取模拟 AWS 文件的测试时 jest 超时?
Why does jest time out when running a test on mock AWS file read?
我正在尝试编写单元测试(开玩笑)来测试服务的执行情况。目前,测试超时,我肯定它与我创建读取流的要点有关。我嘲笑 s3.getObject.createReadStream() 正确吗?
handler.ts
const XLSX = require("xlsx");
const AWS = require("aws-sdk");
import { Pool } from "pg";
class Service {
client: any;
workbook: any = "";
constructor(client) {
this.workbook = "";
this.client = client;
}
async createWorkbookFromS3(filePath: string, id: string) {
const fileLocation = id + filePath;
const params = {
Bucket: "bucket",
Key: fileLocation,
};
function getBufferFromS3(callback) {
const buffers = [];
const s3 = new AWS.S3();
const stream = s3.getObject(params).createReadStream();
stream.on("data", (data) => buffers.push(data));
stream.on("end", () => callback(null, Buffer.concat(buffers)));
stream.on("error", (error) => callback(error));
}
function getBufferFromS3Promise() {
return new Promise((resolve, reject) => {
getBufferFromS3((error, s3buffer) => {
if (error) {
return reject(error)
};
return resolve(s3buffer);
});
});
}
try {
const buffer = await getBufferFromS3Promise();
this.workbook = XLSX.read(buffer);
} catch (e) {
if (e) {
this.client.release()
console.error(e);
throw new Error("Unable to read the xlsx from S3");
}
}
}
}
const decoder = async (event: any) => {
const id: string = event.body["id"];
const filePath = `${id}.xlsx`;
try {
switch (event.path) {
case "/vsiDecoder/draft":
try {
const filePath: string = event.body["filePath"];
const dbCredentials = {"user":"postgres","password":"password","host":"awsconnectihoststring","port": "0000" ,"database":"db"}
const pool = new Pool(JSON.parse(dbCredentials['SecretString']));
const client = await pool.connect();
const vsiObj = new Service(client);
await vsiObj.createWorkbookFromS3(filePath, id);
vsiObj.client.release()
pool.end();
} catch (e) {
throw new Error(e)
}
return {
statusCode: 200,
message: "The document has been successfully drafted.",
};
default:
return {
message: "Bad request",
statusCode: 400,
};
}
} catch (e) {
console.log(e)
return{
statusCode: 400,
message: e.message,
}
}
};
module.exports = {Service, decoder }
handler.test.ts
const decoder = require('./handler.ts')
import { Pool } from 'pg';
const mockgetObject = {
createReadStream: jest.fn(() => {
return {
on: jest.fn()
}
})
}
const mockS3Instance = {
putObject: jest.fn().mockReturnThis(),
promise: jest.fn().mockReturnThis(),
catch: jest.fn(),
getObject: jest.fn(() => mockgetObject)
}
jest.mock('aws-sdk', () => {
return {
S3: jest.fn(() => mockS3Instance),
}
});
jest.mock('pg', () => {
const mClient = {
connect: jest.fn().mockReturnThis(),
query: jest.fn().mockReturnThis(),
end: jest.fn().mockReturnThis(),
release: jest.fn().mockReturnThis(),
};
return { Pool: jest.fn(() => mClient) };
});
describe('Service Test', () => {
let client;
beforeEach(() => {
client = new Pool();
jest.setTimeout(30000);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should executre decoder', async () => {
const id = 'id';
const filePath = 'filePath'
const service = new decoder.Service(client);
await service.createWorkbookFromS3(id, filePath)
const events = { 'body': { 'id': '1234', "path": "/decoder/draft", "vsiFilePath": "path" } };
const response = '{"statusCode":200,"message":"The document has been succesfully drafted."}';
expect((await decoder.decoder(events)).body).toEqual(response);
})
})
错误:
Service Test › should executre decoder
: Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Error:
感谢任何帮助!我确实相信我成功地模拟了 createReadStream 但如果有一种方法可以模拟 getBufferFromS3Promise 那将是可以接受的。
在您的 createReadStream
mock 中,on
函数没有实现。但是,在 getBufferFromS3(callback)
的代码中,on
函数负责设置执行回调函数的事件处理程序,这是来自 getBufferFromS3Promise
的 Promise 将被解决或拒绝的地方。因为该承诺永远不会被解决或拒绝,所以您的异步测试代码永远不会完成。
您需要实现 on
函数的模拟,它将以某种方式执行事件处理程序回调。如果您只是测试成功案例,您可以在 on
内同步执行处理程序,因为 'end' 事件恰好在 'error' 事件之前连接。更好的方法可能是通过 on
保存处理程序来模拟事件发射器,并向流模拟添加 triggerEvent
函数,允许您在测试中强制触发不同的流事件。
我正在尝试编写单元测试(开玩笑)来测试服务的执行情况。目前,测试超时,我肯定它与我创建读取流的要点有关。我嘲笑 s3.getObject.createReadStream() 正确吗?
handler.ts
const XLSX = require("xlsx");
const AWS = require("aws-sdk");
import { Pool } from "pg";
class Service {
client: any;
workbook: any = "";
constructor(client) {
this.workbook = "";
this.client = client;
}
async createWorkbookFromS3(filePath: string, id: string) {
const fileLocation = id + filePath;
const params = {
Bucket: "bucket",
Key: fileLocation,
};
function getBufferFromS3(callback) {
const buffers = [];
const s3 = new AWS.S3();
const stream = s3.getObject(params).createReadStream();
stream.on("data", (data) => buffers.push(data));
stream.on("end", () => callback(null, Buffer.concat(buffers)));
stream.on("error", (error) => callback(error));
}
function getBufferFromS3Promise() {
return new Promise((resolve, reject) => {
getBufferFromS3((error, s3buffer) => {
if (error) {
return reject(error)
};
return resolve(s3buffer);
});
});
}
try {
const buffer = await getBufferFromS3Promise();
this.workbook = XLSX.read(buffer);
} catch (e) {
if (e) {
this.client.release()
console.error(e);
throw new Error("Unable to read the xlsx from S3");
}
}
}
}
const decoder = async (event: any) => {
const id: string = event.body["id"];
const filePath = `${id}.xlsx`;
try {
switch (event.path) {
case "/vsiDecoder/draft":
try {
const filePath: string = event.body["filePath"];
const dbCredentials = {"user":"postgres","password":"password","host":"awsconnectihoststring","port": "0000" ,"database":"db"}
const pool = new Pool(JSON.parse(dbCredentials['SecretString']));
const client = await pool.connect();
const vsiObj = new Service(client);
await vsiObj.createWorkbookFromS3(filePath, id);
vsiObj.client.release()
pool.end();
} catch (e) {
throw new Error(e)
}
return {
statusCode: 200,
message: "The document has been successfully drafted.",
};
default:
return {
message: "Bad request",
statusCode: 400,
};
}
} catch (e) {
console.log(e)
return{
statusCode: 400,
message: e.message,
}
}
};
module.exports = {Service, decoder }
handler.test.ts
const decoder = require('./handler.ts')
import { Pool } from 'pg';
const mockgetObject = {
createReadStream: jest.fn(() => {
return {
on: jest.fn()
}
})
}
const mockS3Instance = {
putObject: jest.fn().mockReturnThis(),
promise: jest.fn().mockReturnThis(),
catch: jest.fn(),
getObject: jest.fn(() => mockgetObject)
}
jest.mock('aws-sdk', () => {
return {
S3: jest.fn(() => mockS3Instance),
}
});
jest.mock('pg', () => {
const mClient = {
connect: jest.fn().mockReturnThis(),
query: jest.fn().mockReturnThis(),
end: jest.fn().mockReturnThis(),
release: jest.fn().mockReturnThis(),
};
return { Pool: jest.fn(() => mClient) };
});
describe('Service Test', () => {
let client;
beforeEach(() => {
client = new Pool();
jest.setTimeout(30000);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should executre decoder', async () => {
const id = 'id';
const filePath = 'filePath'
const service = new decoder.Service(client);
await service.createWorkbookFromS3(id, filePath)
const events = { 'body': { 'id': '1234', "path": "/decoder/draft", "vsiFilePath": "path" } };
const response = '{"statusCode":200,"message":"The document has been succesfully drafted."}';
expect((await decoder.decoder(events)).body).toEqual(response);
})
})
错误:
Service Test › should executre decoder
: Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Error:
感谢任何帮助!我确实相信我成功地模拟了 createReadStream 但如果有一种方法可以模拟 getBufferFromS3Promise 那将是可以接受的。
在您的 createReadStream
mock 中,on
函数没有实现。但是,在 getBufferFromS3(callback)
的代码中,on
函数负责设置执行回调函数的事件处理程序,这是来自 getBufferFromS3Promise
的 Promise 将被解决或拒绝的地方。因为该承诺永远不会被解决或拒绝,所以您的异步测试代码永远不会完成。
您需要实现 on
函数的模拟,它将以某种方式执行事件处理程序回调。如果您只是测试成功案例,您可以在 on
内同步执行处理程序,因为 'end' 事件恰好在 'error' 事件之前连接。更好的方法可能是通过 on
保存处理程序来模拟事件发射器,并向流模拟添加 triggerEvent
函数,允许您在测试中强制触发不同的流事件。