如何在 Mongo(ose)/Express 应用程序中测试 Promise?

Posted

技术标签:

【中文标题】如何在 Mongo(ose)/Express 应用程序中测试 Promise?【英文标题】:How to test promises in Mongo(ose)/Express app? 【发布时间】:2014-05-14 09:07:03 【问题描述】:

我正在使用 Promise 在 (expressJS) 路由的末尾包装异步 (Mongo) 数据库操作。 我想尝试弄清楚如何测试以下代码。

用户服务

userService.findOne = function (id) 

    var deferred = q.defer();

    User.findOne("_id" : id)
        .exec(function (error, user) 
            if (error) 
                deferred.reject(error);
             else 
                deferred.resolve(user);
            
        );

    return deferred.promise;
;

用户路由

var user = function (req, res) 
    var userId = req.params.id
         , userService = req.load("userService");
         // custom middleware that enables me to inject mocks

    return userService.findOne(id)
        .then(function (user) 
            console.log("called then");
            res.json(
                msg: "foo"
            );
        ).catch(function (error) 
            console.log("called catch");
            res.json(
                error: error
            );
        ).done();
;

这里尝试用 mocha 测试上述内容

用户测试

it("when resolved", function (done) 

    var jsonSpy = sinon.spy(httpMock.res, "json")
        , httpMock = require("/path/to/mock/http/object")
        , serviceMock = require("/path/to/mock/service"),
        , deferred = q.defer()
        , findStub = sinon.stub(serviceMock, "findOne")
            .returns(deferred.promise)
        , loadStub = sinon.stub(httpMock.req, "load")
            .returns(serviceMock),
        retPromise;


    // trigger route
    routes.user(httpMock.req, httpMock.res);

    // force promise to resolve?
    deferred.resolve(); 

    expect(jsonSpy.called).to.be.true; // fails

    // chai as promised 
    retPromise = findStub.returnValues[0];
    expect(retPromise).to.be.fulfilled; // passes
);

http mock 只是一个没有操作的空对象,expressJS 通常会在其中开始渲染内容。我在这些无操作中添加了一些日志记录,以了解它们是如何联系在一起的。

这真的行不通。我想验证整体是如何集成的,以建立某种回归套件 - 但我已经有效地将它模拟成碎片,我只是在测试我的模拟(并不完全成功)。

我还注意到我的 http 模拟中的控制台日志由 then 和 catch 触发两次 - 但是在实际代码中调用的 jsonSpy(通过注销 userRoute 代码中的 sinon spy 来验证)不是在测试中调用。

有没有人对 Mongo 支持的快速应用程序的集成测试策略提出一些建议?

【问题讨论】:

从最近开始,您可以从 mocha 测试中 return 承诺并让测试成功拒绝,而不必在履行处理程序中显式调用 done() 并在拒绝处理程序中显式失败。顺便检查一下 chai 的承诺断言 如果您查看我的示例,您会发现我已经在使用 Chai-as-promised 为了 100% 公平,我看到你是 - 我只是想把它偷偷放在这里,因为人们将来可能会遇到这个问题,我希望明确指出。顺便说一句,好问题,会分享我自己的经验,但我希望 Domenic 能出现并分享他的见解。 【参考方案1】:

在我看来,在您检查结果是否已被调用之前,您并没有给您的承诺一个触发的机会。在设置 jsonSpy.call 之前,您需要异步等待 userService.findOne() 的承诺链完成。试试这个:

    // start of code as normal

    q.when(
        routes.user(httpMock.req, httpMock.res),
        function()  expect(jsonSpy.called).to.be.true; 
    );

    deferred.resolve();

    // rest of code as normal

这应该链接 routes.user() 承诺并按预期通过。

提醒一句:我不熟悉你的框架,所以我不知道它是否会耐心等待所有异步事件发生。如果它给你回拨到你的延迟链带来问题,你可能想尝试nodeunit,它可以很好地处理异步测试(IMO)。

【讨论】:

以上是关于如何在 Mongo(ose)/Express 应用程序中测试 Promise?的主要内容,如果未能解决你的问题,请参考以下文章

让 Mongo 连接到 Express 应用程序

应用安全 - 数据库 | 工具 - mongo数据库 - mongo-express - 漏洞 - 汇总

你能告诉我 express-mongo-sanitize 是不是有效吗?

NodeJS + Express + Mongo Session 存储

如何从服务器端 express/mongo/mongoose 中的 URL,客户端的 axios/react/redux 中获取参数 ID

Node.js + express web应用如何打包部署?