0

Here is my function, in this function, there are two promise function in the 'start' function. How should I test the 'start' function.

export class TTT{

fun1(){
    return new Promise(((resolve, reject) => {
        console.log('function1');
        resolve('function1');
    }))
}

fun2(param){
    return new Promise(((resolve, reject) => {
        console.log('function2');
        resolve(param);
    }))
}

fun3(param){
    console.log('function3');
    return param;
}


async start(){
    let param1 = await this.fun1();
    let param2 = await this.fun2(param1);
    this.fun3(param2);

}
}

And the next test file was wrote by myself. I stub fun1, fun2, and fun3, but it seems only first function works.

   describe('test',function () {
    it('test ', function () {
        let stub_fun1 = 
sinon.stub(TTT.prototype,'fun1').callsFake((param)=>{
        console.log('fun1');
        return (Promise.resolve('fun1'));
    });

    let stub_fun2 = 
sinon.stub(TTT.prototype,'fun2').callsFake((param)=>{
        console.log('fun2');
        return (Promise.resolve('fun2'));
    });

    let stub_fun3 = 
sinon.stub(TTT.prototype,'fun3').callsFake((param)=>{
        console.log('fun3');
        return 'fun3';
    });


    let handler = new TTT();
    let param = handler.start();
    console.log(param);

    stub_fun1.restore();
    stub_fun2.restore();
    stub_fun3.restore();
});

});

And, the result is

test

fun1

Promise { }

✓ test

function2

function3

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
lily
  • 23
  • 4

2 Answers2

0

The test contains race conditions. Stubs are restored before they are called.

start() promise should be chained:

it('test ', async function () {
    ...
    let handler = new TTT();
    let param = await handler.start();
    ...
});

Current setup requires restore() to be called manually. Stubs won't be restored in case a test fails. mocha-sinon can be used to omit restore(), set up a sandbox for each test and restore stubs automatically.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
0

async start is promise function so in your test, you need to tell mocha by specifying await so it will run console.log after this function execution is finished.

describe('test', function () {
  beforeEach(function() {
    sinon.stub(TTT.prototype, 'fun1').callsFake((param)=>{
        console.log('fun1');
        return (Promise.resolve('fun1'));
    });
    sinon.stub(TTT.prototype, 'fun2').callsFake((param)=>{
        console.log('fun2');
        return (Promise.resolve('fun2'));
    });
    sinon.stub(TTT.prototype, 'fun3').callsFake((param)=>{
        console.log('fun3');
        return 'fun3';
    });
  })

  afterEach(function() {
    sinon.restore(); // use single restore
  })

  it('test ', async function () { // specify `async`
    let handler = new TTT();
    let param = await handler.start(); // specify `await`
    console.log(param);  
  });
});

The output

test
fun1
fun2
fun3
undefined
    ✓ test


  1 passing (13ms)
deerawan
  • 8,002
  • 5
  • 42
  • 51
  • Yes, this way can solve my problem. And also can use sandbox method to solve it. In sandbox way, could not use async and await. var sandbox; beforeEach(function () { sandbox = sinon.sandbox.create(); }); afterEach(function () { sandbox.restore(); }); it('should restore all mocks stubs and spies between tests', function() { sandbox.stub(some, 'method'); // note the use of "sandbox" } – lily Aug 24 '18 at 08:57
  • if you use the latest Sinon 5, you don't need to use Sandbox for simple case like above code. https://sinonjs.org/releases/v6.1.5/sandbox/ => "Since sinon@5.0.0, the sinon object is a default sandbox. Unless you have a very advanced setup or need a special configuration, you probably want to just use that one." :) – deerawan Aug 24 '18 at 17:24