首页 > 解决方案 > 为什么我的 sinon 存根表现得像在调用真正的函数?

问题描述

我正在尝试遵循以下示例:https : //www.alexjamesbrown.com/blog/development/stubbing-middleware-testing-express-supertest/ 但 sinon 存根似乎没有执行包装的代码。我看过很多关于这个问题的 stackoverflow 帖子,但没有一个答案能帮助我弄清楚我做错了什么。每当我运行测试时,都会出现以下错误:

1) should return a list of sites

0 通过 (42ms) 1 失败

  1. GET /api/config/buildPro/sites 应该返回一个站点列表:错误:预期 200“OK”,在 Test._assertStatus (node_modules\supertest\lib\test.js:268:12) 处得到 403“Forbidden” ._assertFunction (node_modules\supertest\lib\test.js:283:11) 在 Test.assert (node_modules\supertest\lib\test.js:173:18) 在 Server.localAssert (node_modules\supertest\lib\test.js :131:12) 在emitCloseNT (net.js:1655:8) 在 processTicksAndRejections (internal/process/task_queues.js:83:21)

这让我相信它不是调用存根代码,而是执行实际的授权函数。这是我的代码:

应用程序.js

const express = require('express');
const app = express();
const authorization = require('./security/authorization');

const configRoutes = require('./api/routes/config');

app.all('/api/*', authorization.authorize);
app.use('/api/config', configRoutes);

module.exports = app;

授权.js

const aad = require('azure-ad-jwt');

module.exports.authorize = (req, res, next) => {
    if(!req.headers.authorization){
        res.status(403).json({
            message: "Auth failed"
        });
        return;
    }

    const jwtToken = req.headers.authorization.replace('Bearer ', '');

    aad.verify(jwtToken, null, function (err, result) {
        if (result) {
            next();
        } else {
            res.status(401).json({
                message: "Auth failed"
            });
        }
    });
};

config.spec.js

const request = require('supertest');
const sinon = require('sinon');
const app = require('../app');
const authorization = require('../security/authorization');

var agent;

describe('GET /api/names', () => {
    before(() => {
        ensureAuthenticatedSpy = sinon.stub(authorization, 'authorize');

        ensureAuthenticatedSpy.callsArgWithAsync(2);

        agent = require('supertest')
            .agent(require('../app'));
    });

    it('should return a list of names', done => {
        agent
            .get('/api/config/buildPro/sites')
            .expect(200)
            .end((err, res) => {
                if (err) return done(err);
                done();
            });
    });
});

标签: node.jsexpressmocha.jssinonsupertest

解决方案


而是执行实际授权

这正是正在发生的事情。

请注意服务器中的此代码:

app.all('/api/*', authorization.authorize);

这解决authorize了此特定程序状态下的函数引用,并且 express 将使用此特定函数(原始函数!)用于程序的其余部分。

这个:

ensureAuthenticatedSpy = sinon.stub(authorization, 'authorize');

稍后调用,并且考虑到 sinon 无权更改对authorize先前捕获的原始的引用......是无操作的。

IOW,基本 Javascript 应用程序中的依赖注入并不像人们想要的那么简单。

要解决方法,您可以更改原始路线app.js

app.all('/api/*', (req, res, next) => authorization.authorize(req, res, next));

现在,您的闭包将在authorization.authorize每次调用时解析,从而启用您感兴趣的模拟/间谍功能。但是,这种解决方案远非优雅。


推荐阅读