简体   繁体   中英

How to stub a module function that is called from another function

My module.ts file has 2 functions:

export async function foo() {
    var barVal = await bar();
    doSomethingWithBarVal(barVal);
}

export async function bar(): Bar {
    return await somethingAsync();
}

In my tests I want to stub bar() and return a mock for Bar (the returned value of bar() )

My current test looks like this:

var module = require('module.ts');
var myStub = sinon.stub(module, 'bar').resolves(myMock);
await foo();
expect(myStub.calledOnce);

However, the expect always fails and the 'real' bar() is called.
If I call bar() directly from my test, then the stub is called but I want to test the whole flow.

The problem with your approach is that you are stubbing module object ( exports since you are using commonjs require in your test) while your foo function uses bar available in module scope.

To fix this you have a few options here.

1. Quick and dirty

Use exports.bar instead of bar in foo

export async function foo() {
    var barVal = await exports.bar();
    doSomethingWithBarVal(barVal);
}

This approach is actually a hack that uses the fact that your module will be transpiled to commonjs format. Which might be not true someday but kinda works for now.

2. Embrace static nature of ES modules

Embrace the fact that ES modules are static. Make your function "testable again" by explicitly allowing to specify bar as its argument

export async function foo(_bar = bar) {
    var barVal = await _bar();
    doSomethingWithBarVal(barVal);
}

// test.js
await foo(mockBarImplementation)

3. Advanced

Use some IoC/DI implementation. For example typescript-ioc

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