如何用jest同时测试文件和json数据?
How to test files and json data at the same time with jest?
我有一个 post 请求与快递上传一个文件和一些数据到 mongodb:
// Routes
Router.post('/api/training', validator(createVideoSchema, 'body'), uploadVideo, createVideoHandler);
// Route Handlers
async function createVideoHandler (req: Request, res: Response, next: NextFunction) {
try {
const dataToCreate = {
...req.body,
url: req.file?.path,
mimetype: req.file?.mimetype
};
const data = await service.create(dataToCreate);
response(req, res, data, 201);
} catch (error) {
next(error);
}
}
正文必须通过 joi 使用以下模式进行验证:
import Joi from 'joi';
const title = Joi.string().email().min(5).max(255);
const description = Joi.string().min(5).max(255);
const thumbnail = Joi.string().min(5).max(255);
const tags = Joi.array().items(Joi.string().min(5).max(100));
const createVideoSchema = Joi.object({
title: title.required(),
description: description.required(),
thumbnail: thumbnail.required(),
tags: tags.required(),
});
export { createVideoSchema };
然后我正在创建一个测试来验证我收到了 201 状态代码:
it('should have a 201 status code', async () => {
const response = await request(app).post(route)
.set('Accept', 'application/json')
.field('title', data.title)
.field('description', data.description)
.field('thumbnail', data.thumbnail)
.field('tags', data.tags)
.attach('video', Buffer.from('video'), { filename: 'video.mp4' });
expect(response.status).toBe(201);
});
出于某种原因,验证中间件向我抛出 400 错误,提示数据丢失:
Error: "title" is required. "description" is required. "thumbnail" is required. "tags" is required
我尝试使用 .set('Accept', 'multipart/form-data') 发送数据,但它抛出了同样的错误。
我猜这个错误与我发送数据的方式有关,但我不太明白。
您通常不应从测试中调用实时 API。相反,您应该模拟不同的可能 API 响应场景,并确保您的代码正确处理不同的可能性。理想情况下,您还将拥有某种类型的客户端 class,可以将对您的 API 的直接调用置于可以轻松模拟的 class 中。
例如,您可以模拟有效数据的端点响应,例如:
export class VideoClient {
async createVideo(data) {
const response = await request(app).post(route) // Whatever url points to your API endpoint
.set('Accept', 'application/json')
.field('title', data.title)
.field('description', data.description)
.field('thumbnail', data.thumbnail)
.field('tags', data.tags)
.attach('video', Buffer.from('video'), { filename: 'video.mp4' });
if (response.status.ok) {
return { response, message: 'someGoodResponseMessage'};
}
return { response, message: 'someErrorOccurred' };
}
}
然后在你的测试中你可以模拟你的客户端调用:
import { VideoClient } from './clients/VideoClient.js'; // or whatever path you saved your client to
const goodData = { someValidData: 'test' };
const badData = {someBadData: 'test' };
const goodResponse = {
response: { status: 201 },
message: 'someGoodResponseMessage'
}
const badResponse = {
response: { status: 400 },
message: 'someErrorOccurred'
}
it('should have a 201 status code', async () => {
VideoClient.createVideo = jest.fn().mockReturnValue(goodResponse);
const results = await VideoClient.createVideo(goodData);
expect(results.response.status).toBe(201);
expect(results.message).toEqual('someGoodResponseMessage');
});
it('should have a 400 status code', async () => {
VideoClient.createVideo = jest.fn().mockReturnValue(badResponse);
const results = await VideoClient.createVideo(badData);
expect(results.response.status).toBe(400);
expect(results.message).toEqual('someErrorOccurred');
});
这绝不是一个有效的测试或详尽的示例,而是展示了这样的想法,即您真的不应该在测试中调用 API,而是调用 API 的模拟实现来处理您的客户端代码在不同情况下的响应方式。
我有一个 post 请求与快递上传一个文件和一些数据到 mongodb:
// Routes
Router.post('/api/training', validator(createVideoSchema, 'body'), uploadVideo, createVideoHandler);
// Route Handlers
async function createVideoHandler (req: Request, res: Response, next: NextFunction) {
try {
const dataToCreate = {
...req.body,
url: req.file?.path,
mimetype: req.file?.mimetype
};
const data = await service.create(dataToCreate);
response(req, res, data, 201);
} catch (error) {
next(error);
}
}
正文必须通过 joi 使用以下模式进行验证:
import Joi from 'joi';
const title = Joi.string().email().min(5).max(255);
const description = Joi.string().min(5).max(255);
const thumbnail = Joi.string().min(5).max(255);
const tags = Joi.array().items(Joi.string().min(5).max(100));
const createVideoSchema = Joi.object({
title: title.required(),
description: description.required(),
thumbnail: thumbnail.required(),
tags: tags.required(),
});
export { createVideoSchema };
然后我正在创建一个测试来验证我收到了 201 状态代码:
it('should have a 201 status code', async () => {
const response = await request(app).post(route)
.set('Accept', 'application/json')
.field('title', data.title)
.field('description', data.description)
.field('thumbnail', data.thumbnail)
.field('tags', data.tags)
.attach('video', Buffer.from('video'), { filename: 'video.mp4' });
expect(response.status).toBe(201);
});
出于某种原因,验证中间件向我抛出 400 错误,提示数据丢失:
Error: "title" is required. "description" is required. "thumbnail" is required. "tags" is required
我尝试使用 .set('Accept', 'multipart/form-data') 发送数据,但它抛出了同样的错误。
我猜这个错误与我发送数据的方式有关,但我不太明白。
您通常不应从测试中调用实时 API。相反,您应该模拟不同的可能 API 响应场景,并确保您的代码正确处理不同的可能性。理想情况下,您还将拥有某种类型的客户端 class,可以将对您的 API 的直接调用置于可以轻松模拟的 class 中。
例如,您可以模拟有效数据的端点响应,例如:
export class VideoClient {
async createVideo(data) {
const response = await request(app).post(route) // Whatever url points to your API endpoint
.set('Accept', 'application/json')
.field('title', data.title)
.field('description', data.description)
.field('thumbnail', data.thumbnail)
.field('tags', data.tags)
.attach('video', Buffer.from('video'), { filename: 'video.mp4' });
if (response.status.ok) {
return { response, message: 'someGoodResponseMessage'};
}
return { response, message: 'someErrorOccurred' };
}
}
然后在你的测试中你可以模拟你的客户端调用:
import { VideoClient } from './clients/VideoClient.js'; // or whatever path you saved your client to
const goodData = { someValidData: 'test' };
const badData = {someBadData: 'test' };
const goodResponse = {
response: { status: 201 },
message: 'someGoodResponseMessage'
}
const badResponse = {
response: { status: 400 },
message: 'someErrorOccurred'
}
it('should have a 201 status code', async () => {
VideoClient.createVideo = jest.fn().mockReturnValue(goodResponse);
const results = await VideoClient.createVideo(goodData);
expect(results.response.status).toBe(201);
expect(results.message).toEqual('someGoodResponseMessage');
});
it('should have a 400 status code', async () => {
VideoClient.createVideo = jest.fn().mockReturnValue(badResponse);
const results = await VideoClient.createVideo(badData);
expect(results.response.status).toBe(400);
expect(results.message).toEqual('someErrorOccurred');
});
这绝不是一个有效的测试或详尽的示例,而是展示了这样的想法,即您真的不应该在测试中调用 API,而是调用 API 的模拟实现来处理您的客户端代码在不同情况下的响应方式。