无法找出笑话代码覆盖率中的问题

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%。它显示 1631 行未被覆盖。

第 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 或您实际想要测试的内容。但是像这样,该行应该被覆盖。但从这个意义上说,报道并不意味着什么。这样的测试并不好。你应该弄清楚你到底想测试什么。这只是为了表明你想要的大致要求。