包含承诺的单元测试处理程序

Unit test handler that contains promise

我有 TDD 知识,并且我一直在尝试应用相同的原则 javascript 开始一个项目。

我正在构建一个 API,一旦命中,就会向外部服务发出请求以收集一些数据,一旦检索到,就会解析它并 returns 响应。

到目前为止,我的传奇一直很不走运,我搜索了很多,我在 SO 上发现的最相似的问题是这个 。但是我没有成功应用相同的解决方案。

我在实现端的实现如下:

//... other handlers
weather(request, response) {
    //... some setup and other calls
    this.externalService.get(externalURL)
        .then(serviceResponse => {
            this.externalResponseParser.parse(serviceResponse)
        });
    //... some more code
}

而在测试方面:

let requester;
let mockParser;
let handler;
let promiseResolve;
let promiseReject;

beforeEach(function () {
    requester = new externalRequesterService();
    mockParser = sinon.createStubInstance(...);

    handler = new someHandler({
        externalService: requester,
        externalResponseParser: mockParser
    });
});

it('returns data', function () {
    sinon.stub(requester, 'get').callsFake((url) => {
        return new Promise((resolve, reject) => {
            // so I can be able to handle when the promise gets resolved
            promiseResolve = resolve;
            promiseReject = reject;
        });
    });

    handler.weather(request, response);

    // assertions of what happens before externalService.get gets called - all green

    promiseResolve(expectedServiceResponse);

    assert.ok(mockExternalResponseParser.parse.calledOnce, 'Expected externalResponseParser.parse to have been called once');
});

在测试的最后一行,它失败了,即使我正在调用我应该调用的。 在某些时候,我添加了一些日志记录,我能够看到 then 块的代码似乎是在测试断言之后执行的,这可能是问题的根源。

我试图找出是否有某种 eventually 可以使用,所以我在解决承诺后的断言是这样的:

assert.eventually(mockExternalResponseParser.parse.calledOnce, 'Expected externalResponseParser.parse to eventually be called once');

但运气不好。

有没有人对缺少的内容有明确的解释?非常感谢

P.S.- 根据要求,请找到我的代码 here 的精简版本。只需 运行 npm install,然后是 npm test 以获得相同的输出。

感谢大家抽出时间。

我最终在 Medium 上找到了这篇非常好的文章,它让我解决了我的问题。它有一个很好的解释,从回调到承诺,这正是我手头的场景。

我已经更新了我创建的关于如何修复它的 github 存储库。

如果您想要 TL;DR,这里只是更改的重点。实施方:

async weather(request, response) {
    //...

    let serviceResponse = await this.requesterService.get(weatherURL);

    //...
};

而在测试方面:

it('returns weather on success', async function () {
    sinon.stub(requester, 'get').callsFake((_) => {
        return new Promise((resolve, _) => {
            resolve(expectedServiceResponse);
        });
    });

    await handler.weather(request, response);

    //...
    assert.ok(mockWeatherParser.parseWeather.calledOnce, 'Expected WeatherParser.parseWeather to have been called once'); // no longer fails here
    //...
});

请记住,在这个例子中,它仍然是同步的。然而,我已经一步一步地改进了我的 API,并且在使用 Promises 迁移到这个同步版本之后,迁移到异步版本要容易得多。无论是在测试还是在实施方面。

如果您遇到同样的问题并需要帮助或有任何疑问,请告诉我。我很乐意提供帮助。