简体   繁体   中英

Mocha / Sinon - Unit testing / stubbing function with child_process.exec inside ES6 Promise

I have a function that returns an ES6 promise for use in another external promise chain. The function scans for wifi networks using child_process.exec. The output from exec is sent via the callback to a synchronous parsing function that will return the output in a formatted object, and then resolve the outer promise:

var exec = require('child_process').exec;

function scan() {
    return new Promise((resolve, reject) => {

        // getCurrent returns a promise
        getCurrent().then(network => {
            exec('iwlist wlan0 scan', function(err, stdout, stderr) {
                (err) ? reject(stderr) : resolve(parseOutput(stdout, network));                 
            });
        })
        .catch(err => {
            reject(err);
        }); 
    }); 
}

The problem is, I can't seem to get sinon stubs working properly to get the stubbed version of exec to be called. Currently I have something along the lines of:

var wifi = require('./wifi');

describe('#scan', function() {

    it('Should scan and return networks object', function() {

        var fakeNetwork = '(fake iwlist output goes here)';  
        var exec = sinon.stub(child_process, 'exec').yields(false, fakeNetwork);
        var getCurrent = sinon.stub(wifi, 'getCurrent').returns(Promise.resolve('current-ssid'));

        wifi.scan().then(function(networks) {
            console.log(networks);
            sinon.assert.calledOnce(getCurrent);
            sinon.assert.calledOnce(exec);
        });

        getCurrent.restore();
        exec.restore();

    });
});

I have also tried stubbing like:

var getCurrent = sinon.stub(wifi, 'getCurrent', function() {
    return Promise.resolve('current-ssid').then(network => {
        exec('iwlist wlan0 scan', function(err, data) {
            return(wifi.parseOutput(data, network));                
        });
    });
});

The behavior seems to be that either exec never gets called, or more strangely, that the stubbed exec does get called, but the 'real' functions get called anyway.

With all of the stubs, all I am really "testing" is the parseOutput method, so should I just ditch testing the 'scan' function completely and only focus on the parse function (which would be simple to test), or is there another way I should be looking at this?

I believe I am just doing something obviously wrong, and have been hitting a wall here for several hours. I'm hoping someone has run into this before and can suggest an alternative/better approach.

you can use stub.yields([arg1, arg2, ...]) sinon stubs guide

here is my code

function getVersioniList() {
    let versionList = new Promise((resolve, reject) => {
        child_process.exec(cmd, function(error, stdout, stderr) {
            if (error) {
                reject(error);
            }
            resolve(stdout);
        });
    });

    return versionList;
}

and unit test code as below

// i like the sandbox, or you can use sinon itself
sandbox = sinon.sandbox.create();
sandbox.stub(child_process, 'exec').yields(undefined, [1, 2, 3]);

assert.equal(await getVersioniList(), [1, 2, 3]);

finally, you can get versionList [1, 2, 3]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM