首页 文章

与sinon假单位测试并不能解决承诺

提问于
浏览
0

我正在学习nodejs并为shelljs函数编写了这个包装器,它实际上似乎按预期工作 .

/**
 * Wrapper for Shelljs.exec to always return a promise
 *
 * @param  {String} cmd - bash-compliant command string
 * @param  {String} path - working directory of the process
 * @param {Object} _shell - alternative exec function for testing.
 * @returns {String}
 * @throws {TypeError}
 */
function shellExec(cmd, path, _shell = shelljs){
    if( typeof _shell.exec !== "function") throw new TypeError('_shell.exec must be a function');
    return new Promise((resolve, reject) => {
        let options =  { cwd: path, silent: true, asyc: true }
        // eslint-disable-next-line no-unused-vars
        return _shell.exec(cmd, options, (code, stdout, stderr) => {
            // shelljs.exec does not always return a code
            if(stderr) {
                return reject(stderr);
            }
            return resolve(stdout);
        });
    });
}

但是,当我尝试对其进行单元测试时,该功能会超时 . 我在测试中读过有关异步代码,promisesasync/await的mochajs文档 . 我想使用sinon fake that returns a promise,我知道它有用 . Mocha告诉我错误是函数没有通过错误 Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves 返回一个promise . 我想我已经错误地构造了假货,但我看不出我应该怎么做 .

const { expect, use } = require('chai');
const sinon = require('sinon');
const sinonChai = require("sinon-chai");
const utils = require('../utility/exec');

use(sinonChai);

it('sinon fake should resolve', async () =>{
    const fake = sinon.fake.resolves('resolved');

    const result = await fake();
    expect(result).to.equal('resolved');
});
describe('Utility Functions', () =>{
    describe('shellExec', () =>{
        it('should accept an alternate execute function', async () =>{
            const fakeShell = { exec: sinon.fake.resolves('pass') };
            const result = await utils.shellExec('pwd', 'xyz', fakeShell);
            expect(result).to.equal('pass');
            expect(fakeShell.exec).to.have.been.calledOnce;
        });
    });
});

2 回答

  • 1

    你的 _shell.exec 只是一个回调函数,它是's not a Promise. That'为什么当你伪造shell.exec作为一个承诺时,你的 resolve 永远不会被调用 . 我认为你需要伪造你的fakeShell,如下所示:

    const fakeShell = { 
       exec: (cmd, options, cb) => {
          cb(true, 'pass', null);
       }
    };
    
  • 1

    你的功能有点复杂,但没有任何sinon无法处理存根 . 有关详细信息,请参阅https://sinonjs.org/releases/v1.17.7/stubs/,但在函数前应使用 callsArgOnWith .

    而不是设置 exec 来返回一个promise,你需要将它设置为存根 . 这样,您可以在遇到时使用 callsArgOnWith 函数调用回调 .

    我已经改变了你的测试,所以它现在通过改变假的 exec 函数来返回一个存根 const fakeShell = { exec: sinon.stub() }; 并在运行你的函数之前添加行 fakeShell.exec.callsArgOnWith(2, null, null, 'pass', null)

    const { expect, use } = require('chai');
    const sinon = require('sinon');
    const sinonChai = require("sinon-chai");
    const utils = require('./main');
    
    
    use(sinonChai);
    
    it('sinon fake should resolve', async () =>{
        const fake = sinon.fake.resolves('resolved');
    
        const result = await fake();
        expect(result).to.equal('resolved');
    });
    describe('Utility Functions', () =>{
        describe('shellExec', () =>{
            it('should accept an alternate execute function', async () =>{
                const fakeShell = { exec: sinon.stub() };
                fakeShell.exec.callsArgOnWith(2, null, null, 'pass', null)
                const result = await utils.shellExec('pwd', 'xyz', fakeShell);            
                expect(result).to.equal('pass');
                expect(fakeShell.exec).to.have.been.calledOnce;
            });
        });
    });
    

相关问题