繁体   English   中英

如何在模块中存根函数?

[英]How to stub a function in a module?

我建立快递应用程序,有一条路线A使用许多中间件:

// fblogin.js
const saveUser = require('./middlewares').saveUser;
const issueJWT = require('./middlewares').issueJWT;

const exchangeLongTimeToken = (a) => { //return promise to call API };
const retrieveUserInfo = (b) => { //return promise to call API };

const service = {
    exchangeLongTimeToken,
    retrieveUserInfo,
};

const asyncAll = (req, res) => { 
    // use Promise.all() to get service.exchangeLongTimeToken 
    // and service.retrieveUserInfo
};

router.post('/', [asyncAll, saveUser, issueJWT], (req, res) => {
    //some logic;
});

module.exports = { router, service };

这是我的middlewares.js

const saveUser = (req, res, next) => { //save user };
const issueJWT = (req, res, next) => { //issue jwt };

module.exports = { saveUser, issueJWT };

它运作良好。 但是当我尝试编写测试时遇到了问题。 这是我的测试,我使用mocha,chai,supertest和sinon:

const sinon = require('sinon');
const middlewares = require('../../../../src/routes/api/auth/shared/middlewares');
const testData = require('../../testdata/data.json');
let app = require('../../../../src/config/expressapp').setupApp();
const request = require('supertest');
let service = require('../../../../src/routes/api/auth/facebook/fblogin').service;


describe('I want to test', () => {
    context('Let me test', function () {
        const testReq = {name: 'verySad'};

        beforeEach(() => {
            sinon.stub(middlewares, 'saveUser').callsFake((req, res, next)=>{
                console.log(req);
            });


            sinon.stub(service, 'exchangeLongTimeToken').callsFake((url) => {
                return Promise.resolve(testData.fbLongTimeToken);
            });

            sinon.stub(service, 'retrieveUserInfo').callsFake((url) => {
                return Promise.resolve(testData.fbUserInfo);
            });

        });


        it('Should return 400 when bad signedRequest', () => {

            return request(app).post(facebookAPI).send(testReq).then((response) => {
                response.status.should.be.equal(400);
            });
        });
});

问题是什么
您可能会看到有3个存根,其中1个是middlewares.saveUser ,2个是services.XXXX ,它们在路由的同一文件中。

问题在于,2个存根有效,而middlewares.saveUser .saveUser的1个存根不起作用,总是触发原始存根。

我认为也许当我调用setupApp() ,Express会加载它需要的所有路由器,因此之后对其进行模拟不会产生任何效果,但是奇怪的是route.service可以被route.service ...

如何使存根工作?
使它工作的唯一方法是,将存根放在测试文件的顶部, middleware需求之后。

我试过了:
1.使用第三方的模块,如proxyquirerewire
2.使用节点自己的delete require.cache[middlewares]和'app'并重新请求它们。
3.许多其他技巧。
4.使用jest的模拟,但仅当我将其放在文件顶部时仍然有效。

在不将存根放在测试文件顶部的情况下,如何解决此问题? 谢谢!

这个问题的解决方案有点受限制,因为该模拟已经污染了整个测试套件。

最后,我这样做了,逻辑很简单,我们仍然需要先模拟saveUser ,但是我们需要将所有其他变量放入测试函数中,而不是要求它们位于文件顶部,这一次更加灵活。 然后我添加了一个checkIfTheStubWorks方法来检查存根是否正常工作,以确保整个测试都能正常进行。

const middlewares = require('../../../../src/routes/api/auth/shared/middlewares');
const removeEmptyProperty = require('../../../../src/utils/utils').removeEmptyProperty;

let app;
let service;
let request;

/*
 * The reason we need this is:
 * If the mock not works,
 * the whole test is meaningless
 */
const checkIfTheStubWorks = () => {
    expect(spy1).toHaveBeenCalled();
    expect(spy2).toHaveBeenCalled();
    expect(spy3).toHaveBeenCalled();
};

const loadAllModules = () => {
    service = require('../../../../src/routes/api/auth/facebook/fblogin').service;
    app = require('../../../../src/config/expressapp').setupApp();
    request = require('supertest')(app);
};

describe('Mock response from facebook', () => {
    let spy1 = {};
    let spy2 = {};
    let spy3 = {};
    const testReq = testData.fbShortToken;

beforeAll(() => {
    spy1 = jest.spyOn(middlewares, 'saveUser').mockImplementation((req, res, next) => {
        userToSaveOrUpdate = removeEmptyProperty(res.locals.user);
        next();
    });

    // It must be load here, in this order,
    // otherwise, the above mock won't work!
    loadAllModules();

    spy2 = jest.spyOn(service, 'exchangeLongTimeToken').mockImplementation((url) => {
        // mock it
    });

    spy3 = jest.spyOn(service, 'retrieveUserInfo').mockImplementation((url) => {
        // mock it
    });
});

afterAll(() => {
    spy1.mockRestore();
    spy2.mockRestore();
    spy3.mockRestore();
});

test('Return a JWT should have same length as facebook one', async () => {
    const response = await request.post(facebookAPI).send(testReq);
    // assert this, assert that 
    checkIfTheStubWorks();
});
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM