开玩笑-函数fs.writefile中的模拟回调

时间:2020-10-07 19:21:10

标签: node.js callback jestjs mocking

我在这个话题上坚持了3个小时。我找不到在此代码中如何测试if(err)分支的解决方案:

    function createFile(data){

return new Promise(function(resolve, reject) {

    try {

        if(data === null || data === undefined){
            throw new Error(errorMessages.noDataDefined);
        }

        let internalJobId = uuid.v4();
        let fileName = 'project_name' + internalJobId + '.xml';

        fs.writeFile(config.tmpPath + fileName, data, function (err) {
            if (err){
                throw new Error(err.toString());
            } else {
                resolve(fileName);
            }
            
        });

    } catch (error) {
        return reject(error);
    }
});

}

此测试通过,但未调用if(err){抛出新错误(err.toString())}

我必须找到解决方案,回调如何返回错误,但是我没有找到正确的解决方案。

test('Error', () => {

    jest.mock('fs', () => ({
        writeFile: jest.fn((path, data, callback) => callback(Error('some error')))
      }));

    return expect(createFile('Does not matter')).rejects.toThrow('some error');


});

但是通过此测试,甚至没有拒绝,因此永远不会抛出错误。如果有人可以帮助我,我将不胜感激。

2 个答案:

答案 0 :(得分:1)

这里有两个问题。一种是fs.writeFile未被正确模拟。另一个是createFile无法正确处理错误,无法满足期望。

jest.mock影响尚未导入并提升到块顶部(或在顶层使用时高于导入)的模块。如果已经导入了使用fs的模块,则它不会影响fs。由于// at top level import fs from 'fs'; jest.mock('fs', ...); ... 函数通常与其名称空间一起使用,因此也可以将它们模拟为方法。

应该是:

// inside test
jest.spyOn(fs, 'writeFile').mockImplementation(...);
...

或者:

expect(fs.writeFile).toBeCalledTimes(1);
expect(fs.writeFile).toBeCalledWith(...);
return expect(createFile('Does not matter'))...

并断言要使测试更具体:

try..catch

Promise构造函数不需要reject,因为它已经捕获了其中的所有 synchronous 错误,并且无法捕获回调中的异步错误。对于需要兑现承诺的地方,fs.writeFile可以保持一致性。

try..catch回调中引发错误是一个错误,并导致未完成的Promise。它没有机会拒绝诺言,也没有机会在回调之外被function createFile(data){ return new Promise(function(resolve, reject) { if(data === null || data === undefined){ reject(new Error(errorMessages.noDataDefined)); } let internalJobId = uuid.v4(); let fileName = 'project_name' + internalJobId + '.xml'; fs.writeFile(config.tmpPath + fileName, data, function (err) { if (err){ reject(new Error(err.toString()); // reject(err) ? } else { resolve(fileName); } }); }); } 捕获,并导致未捕获的错误。

应该是:

async

为了使嵌套最少,可以将不需要多余的部分移到构造函数之外,并使用async function createFile(data){ if(data === null || data === undefined){ throw new Error(errorMessages.noDataDefined); } return new Promise(function(resolve, reject) { let internalJobId = uuid.v4(); ... 函数:

new Error(err.toString())

也可能不需要fs.promises API

还要注意,err可能不必要,并且会导致意外的错误消息,从而使声明失败。可以用new Error(err.message)拒绝诺言。如果要删除不必要的错误信息或更改错误堆栈,则应为{{1}}。

答案 1 :(得分:0)

解决方案是:

 jest.spyOn(fs, 'writeFile').mockImplementation((f, d, callback) => {
                callback('some error');
 });
    

感谢Estus Flask!