无法找出笑话代码覆盖率中的问题
Not able to figure out issue in jest code coverage
我的 nestjs 中有以下文件。
import { extname } from 'path';
import { diskStorage } from 'multer';
import { v4 as uuid } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';
export const multerConfig = {
dest: process.env.UPLOAD_LOCATION,
};
export const multerOptions = {
limits: {
fileSize: +process.env.MAX_FILE_SIZE,
},
fileFilter: (_req: any, file: any, cb: any) => {
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
} else {
cb(
new HttpException(
`Unsupported file type ${extname(file.originalname)}`,
HttpStatus.BAD_REQUEST
),
false
);
}
},
storage: diskStorage({
destination: multerConfig.dest,
filename: (_req: any, file: any, cb: any) => {
cb(null, `${uuid()}${extname(file.originalname)}`);
},
}),
};
我为它写了下面的测试用例。
import { Readable } from 'stream';
import { multerConfig, multerOptions } from './multer.config';
describe('Multer Configuration ', () => {
const mockFile: Express.Multer.File = {
filename: '',
fieldname: '',
originalname: '',
encoding: '',
mimetype: '',
size: 1,
stream: new Readable(),
destination: '',
path: '',
buffer: Buffer.from('', 'utf8'),
};
it('should define destination', () => {
expect(multerConfig).toBeDefined();
expect(multerConfig.dest).toBe(process.env.UPLOAD_LOCATION);
});
it('should define multer upload options', async () => {
expect(multerOptions).toBeDefined();
expect(multerOptions.fileFilter).toBeDefined();
expect(multerOptions.storage).toBeTruthy();
expect(multerOptions.limits).toBeTruthy();
const cb = jest.fn();
multerOptions.fileFilter({}, mockFile, cb);
expect(cb).toHaveBeenCalled();
expect(cb).toHaveBeenCalledTimes(1);
expect(cb()).toBeFalsy();
});
afterAll(() => {
jest.resetAllMocks();
});
});
两个测试用例都成功了,但是当我检查代码覆盖率时,它只显示了 50%。它显示 16
和 31
行未被覆盖。
第 16 行是
cb(null, true); it comes inside the `if` block
第 31 行是
cb(null, `${uuid()}${extname(file.originalname)}`);
你能帮我看看这部分怎么写吗?我真的很挣扎。
我需要额外的测试用例还是需要修改现有的测试用例?
编辑 1:-
const fileType = 'jpg';
it('should define filetype', async () => {
const cb = jest.fn();
process.env.FILE_TYPE = 'jpg';
multerOptions.fileFilter({}, mockFile, cb);
expect(cb).toHaveBeenCalled();
expect(cb).toHaveBeenCalledTimes(1);
expect(cb()).toBeFalsy();
});
测试用例成功。但覆盖范围和线路仍然相同
您第一个未涵盖的代码部分来自您对 mime 类型使用模式匹配这一事实。
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
}
因此您需要创建一个测试,以使用其中一种 MIME 类型创建模拟文件。
例如,如下所示。虽然,在良好的测试设置中,您可能希望将所有这些扩展作为测试用例进行测试。也许使用某种 table 驱动测试方法。
const mockFile: Express.Multer.File = {
mimetype: 'jpg',
// other stuff
};
似乎在您的测试中,该函数总是进入 else 块,这会引发 HTTP 异常。
您的第二个问题是您没有在测试中使用 options.storage。并且您还提供了一些可以调用该函数的选项。
可能的话,您可以在测试中像下面这样调用它。
const upload = multer(multerOptions).single('somefile');
如果您不想这样做,您可以将回调移动到命名函数中并分配它。
export function filename(_req: any, file: any, cb: any) {
cb(null, `${uuid()}${extname(file.originalname)}`);
}
export const multerOptions = {
storage: diskStorage({
destination: multerConfig.dest,
filename,
}),
}
然后您可以在您的测试设置中自行测试文件名函数。
或者你想办法在存储对象上自行调用文件名函数。我不知道multer
,所以我不知道这是否可能。您需要查阅文档。
总的来说,这可能是这样的。
import { extname } from 'path';
import { diskStorage } from 'multer';
import { v4 as uuid } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';
export const multerConfig = {
dest: process.env.UPLOAD_LOCATION,
};
export function filename(_req: any, file: any, cb: any) {
cb(null, `${uuid()}${extname(file.originalname)}`);
};
export const multerOptions = {
limits: {
fileSize: +process.env.MAX_FILE_SIZE,
},
fileFilter: (_req: any, file: any, cb: any) => {
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
} else {
cb(
new HttpException(
`Unsupported file type ${extname(file.originalname)}`,
HttpStatus.BAD_REQUEST
),
false
);
}
},
storage: diskStorage({
destination: multerConfig.dest,
filename,
}),
};
然后在你的测试中这样。
import { Readable } from 'stream';
import { multerConfig, multerOptions, filename } from './multer.config';
describe('Multer Configuration ', () => {
const mockFile: Express.Multer.File = {
filename: 'foo.jpg', // give it a name
fieldname: '',
originalname: '',
encoding: 'utf8',
mimetype: 'jpg', // give it a mime type
size: 1,
stream: new Readable(),
destination: '',
path: '',
buffer: Buffer.from('', 'utf8'),
};
it('should define destination', () => {
expect(multerConfig).toBeDefined();
expect(multerConfig.dest).toBe(process.env.UPLOAD_LOCATION);
});
it('should define multer upload options', async () => {
expect(multerOptions).toBeDefined();
expect(multerOptions.fileFilter).toBeDefined();
expect(multerOptions.storage).toBeTruthy();
expect(multerOptions.limits).toBeTruthy();
});
// test the filter
it('should filter the file based on mimetype', () => {
const cb = jest.fn();
multerOptions.fileFilter({}, mockFile, cb);
// do something with the callback
});
// test the filename
it('should create the proper filename', () => {
const cb = jest.fn();
filename({}, mockfile, cb)
// do something with the callback
});
afterAll(() => {
jest.resetAllMocks();
});
});
我不确定如何使用 jest 或您实际想要测试的内容。但是像这样,该行应该被覆盖。但从这个意义上说,报道并不意味着什么。这样的测试并不好。你应该弄清楚你到底想测试什么。这只是为了表明你想要的大致要求。
我的 nestjs 中有以下文件。
import { extname } from 'path';
import { diskStorage } from 'multer';
import { v4 as uuid } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';
export const multerConfig = {
dest: process.env.UPLOAD_LOCATION,
};
export const multerOptions = {
limits: {
fileSize: +process.env.MAX_FILE_SIZE,
},
fileFilter: (_req: any, file: any, cb: any) => {
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
} else {
cb(
new HttpException(
`Unsupported file type ${extname(file.originalname)}`,
HttpStatus.BAD_REQUEST
),
false
);
}
},
storage: diskStorage({
destination: multerConfig.dest,
filename: (_req: any, file: any, cb: any) => {
cb(null, `${uuid()}${extname(file.originalname)}`);
},
}),
};
我为它写了下面的测试用例。
import { Readable } from 'stream';
import { multerConfig, multerOptions } from './multer.config';
describe('Multer Configuration ', () => {
const mockFile: Express.Multer.File = {
filename: '',
fieldname: '',
originalname: '',
encoding: '',
mimetype: '',
size: 1,
stream: new Readable(),
destination: '',
path: '',
buffer: Buffer.from('', 'utf8'),
};
it('should define destination', () => {
expect(multerConfig).toBeDefined();
expect(multerConfig.dest).toBe(process.env.UPLOAD_LOCATION);
});
it('should define multer upload options', async () => {
expect(multerOptions).toBeDefined();
expect(multerOptions.fileFilter).toBeDefined();
expect(multerOptions.storage).toBeTruthy();
expect(multerOptions.limits).toBeTruthy();
const cb = jest.fn();
multerOptions.fileFilter({}, mockFile, cb);
expect(cb).toHaveBeenCalled();
expect(cb).toHaveBeenCalledTimes(1);
expect(cb()).toBeFalsy();
});
afterAll(() => {
jest.resetAllMocks();
});
});
两个测试用例都成功了,但是当我检查代码覆盖率时,它只显示了 50%。它显示 16
和 31
行未被覆盖。
第 16 行是
cb(null, true); it comes inside the `if` block
第 31 行是
cb(null, `${uuid()}${extname(file.originalname)}`);
你能帮我看看这部分怎么写吗?我真的很挣扎。 我需要额外的测试用例还是需要修改现有的测试用例?
编辑 1:-
const fileType = 'jpg';
it('should define filetype', async () => {
const cb = jest.fn();
process.env.FILE_TYPE = 'jpg';
multerOptions.fileFilter({}, mockFile, cb);
expect(cb).toHaveBeenCalled();
expect(cb).toHaveBeenCalledTimes(1);
expect(cb()).toBeFalsy();
});
测试用例成功。但覆盖范围和线路仍然相同
您第一个未涵盖的代码部分来自您对 mime 类型使用模式匹配这一事实。
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
}
因此您需要创建一个测试,以使用其中一种 MIME 类型创建模拟文件。
例如,如下所示。虽然,在良好的测试设置中,您可能希望将所有这些扩展作为测试用例进行测试。也许使用某种 table 驱动测试方法。
const mockFile: Express.Multer.File = {
mimetype: 'jpg',
// other stuff
};
似乎在您的测试中,该函数总是进入 else 块,这会引发 HTTP 异常。
您的第二个问题是您没有在测试中使用 options.storage。并且您还提供了一些可以调用该函数的选项。
可能的话,您可以在测试中像下面这样调用它。
const upload = multer(multerOptions).single('somefile');
如果您不想这样做,您可以将回调移动到命名函数中并分配它。
export function filename(_req: any, file: any, cb: any) {
cb(null, `${uuid()}${extname(file.originalname)}`);
}
export const multerOptions = {
storage: diskStorage({
destination: multerConfig.dest,
filename,
}),
}
然后您可以在您的测试设置中自行测试文件名函数。
或者你想办法在存储对象上自行调用文件名函数。我不知道multer
,所以我不知道这是否可能。您需要查阅文档。
总的来说,这可能是这样的。
import { extname } from 'path';
import { diskStorage } from 'multer';
import { v4 as uuid } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';
export const multerConfig = {
dest: process.env.UPLOAD_LOCATION,
};
export function filename(_req: any, file: any, cb: any) {
cb(null, `${uuid()}${extname(file.originalname)}`);
};
export const multerOptions = {
limits: {
fileSize: +process.env.MAX_FILE_SIZE,
},
fileFilter: (_req: any, file: any, cb: any) => {
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
} else {
cb(
new HttpException(
`Unsupported file type ${extname(file.originalname)}`,
HttpStatus.BAD_REQUEST
),
false
);
}
},
storage: diskStorage({
destination: multerConfig.dest,
filename,
}),
};
然后在你的测试中这样。
import { Readable } from 'stream';
import { multerConfig, multerOptions, filename } from './multer.config';
describe('Multer Configuration ', () => {
const mockFile: Express.Multer.File = {
filename: 'foo.jpg', // give it a name
fieldname: '',
originalname: '',
encoding: 'utf8',
mimetype: 'jpg', // give it a mime type
size: 1,
stream: new Readable(),
destination: '',
path: '',
buffer: Buffer.from('', 'utf8'),
};
it('should define destination', () => {
expect(multerConfig).toBeDefined();
expect(multerConfig.dest).toBe(process.env.UPLOAD_LOCATION);
});
it('should define multer upload options', async () => {
expect(multerOptions).toBeDefined();
expect(multerOptions.fileFilter).toBeDefined();
expect(multerOptions.storage).toBeTruthy();
expect(multerOptions.limits).toBeTruthy();
});
// test the filter
it('should filter the file based on mimetype', () => {
const cb = jest.fn();
multerOptions.fileFilter({}, mockFile, cb);
// do something with the callback
});
// test the filename
it('should create the proper filename', () => {
const cb = jest.fn();
filename({}, mockfile, cb)
// do something with the callback
});
afterAll(() => {
jest.resetAllMocks();
});
});
我不确定如何使用 jest 或您实际想要测试的内容。但是像这样,该行应该被覆盖。但从这个意义上说,报道并不意味着什么。这样的测试并不好。你应该弄清楚你到底想测试什么。这只是为了表明你想要的大致要求。