从 Mock FS 开玩笑测试 Node JS 文件错误

Jest testing Node JS file error from Mock FS

我按照基本的例子,使用异步读取文件,无法测试文件读取失败。使用Mock-FS做测试,成功的都通过了,失败的会产生未处理的异常错误。

ReadFileContents.ts

import * as NodeJSFS from 'fs';

export async function ReadFileContents(Directory:string, FileName:string):Promise<string> {
    return new Promise<string>((resolve, reject) => {
        NodeJSFS.readFile(
            `${Directory}/${FileName}`,
            (error: NodeJS.ErrnoException | null, FileContents: Buffer) => {
                if (error) {
                    reject(error);
                } else {
                    resolve(FileContents.toString());
                }
            },
        );
    });
}

ReadFileContents.spec.ts

import * as MockFS from 'mock-fs';
import { ReadFileContents } from './read-file-contents';

describe('ReadFileContents', () => {
    afterAll( async () => {
        MockFS.restore();
    });
    afterEach( async () => {
        MockFS.restore();
    });
    beforeEach( async () => {
        MockFS( {
            'datafiles': {
                'abc.txt': '{ "FirstLine": "This is the first line", "LastLine": "This is the last line" }',
                'abc.hdr': 'Server|MyServer',
            }
        }, {
            // add this option otherwise node-glob returns an empty string!
            createCwd: false
        } );
    });

    it('should have the proper files in the mocked data', () => {
        expect(MockFS.length).toBe(2);
    });

    it('should load the proper file data abc.txt', async () => {
        ReadFileContents('./datafiles', 'abc.txt').then( FileContent => {
            expect(FileContent).toContain('This is the first line');
        });
    });

    it('should load the proper file data from abc.hdr', async () => {
        ReadFileContents('./datafiles', 'abc.hdr').then( FileContent => {
            expect(FileContent).toContain('Server');
        });
    });

    // it('should return an exception when the file does not exist', async () => {
    //  expect(async () => await ReadFileContents('./datafiles', 'FileDoesNotExist.Missing')).not.toThrow();
    // });
});

另外,这个测试也会出现同样的错误:

it('should return an exception when the file does not exist', async () => {
    await expect(ReadFileContents('./datafiles', 'FileDoesNotExist.Missing'))
        .rejects
        .toThrow();
});

上面的错误处理,对于丢失的文件,生成以下错误:

node:internal/process/promises:245
          triggerUncaughtException(err, true /* fromPromise */);
          ^

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Error: EBADF, bad file descriptor".] {
  code: 'ERR_UNHANDLED_REJECTION'
    

如果没有错误条件测试,即使测试通过,我也会收到以下单元测试警告错误。

node:internal/process/promises:245
          triggerUncaughtException(err, true /* fromPromise */);
          ^

[Error: EAGAIN: resource temporarily unavailable, read] {
  errno: -11,
  code: 'EAGAIN',
  syscall: 'read'
}

在 catch 块中,您正在拒绝错误。错误应该是字符串类型,如您所期望的 return 字符串。

我通过对 的回答解决了这个问题。我更改了代码以使用 fs/promises 版本的 readFile。

我将代码更改为:

import * as NodeJSFSPromises from 'fs/promises';
import * as NodeJSPath from 'path';

export async function ReadFileContents(Directory:string, FileName:string):Promise<string> {
    const PathAndFileName = NodeJSPath.format( { dir: Directory, base: FileName });
    const FileContents$:Promise<Buffer> = NodeJSFSPromises.readFile(PathAndFileName);
    const Contents:string = (await FileContents$).toString();
    return Contents;
}