当前位置: 首页 > 知识库问答 >
问题:

如何在模块中存根函数?

施赞
2023-03-14

我创建了express应用程序,有一条路线可以使用许多中间件:

// 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 };

这是我的中间件。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个用于服务。XXXX在路由的同一个文件中。

问题是,2个存根工作,而1个用于<代码>中间件。saveUser不工作,请始终触发原始用户

我想,当我调用setupApp()时,express可能会加载它所需的所有路由器,因此事后模拟它不会产生效果,但奇怪的是路由。服务可能被模拟。。。

如何让存根工作
让它工作的唯一方法是将存根放在测试文件的顶部,就在中间件要求的位置之后。

我试过:
1。使用第三方模块,如proxyquire、rewire。使用节点自己的删除要求。缓存[中间件]和“应用程序”,并重新要求它们
3。许多其他技巧
4。使用jest的mock,但仅当我将其放在文件的顶部时,它仍然有效。

解决这个问题的方法是什么,而不是把存根放在测试文件的顶部?谢谢!

共有1个答案

伯英锐
2023-03-14

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

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

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();
});
});
 类似资料:
  • 我正在尝试使用Cypress存根一个模块。这是我到目前为止尝试过的,但不起作用。 这是我的组件/页面的简短版本 这是我定制的钩子的样子 下面是getData的外观 方法通过db.js(实际上是db/index.js)公开 我正在尝试存根getData。js使e2e测试更加一致。这就是我所做的。 上面的存根不起作用。运行测试时,对外部服务的API调用仍在进行。文档本身让我推断我应该这样写,但它不起作

  • 问题内容: 我正在为node.js代码编写一些单元测试,并且使用Sinon通过以下方式存根函数调用 该是这样的 对于诸如这样的用例,模拟显然可以工作,但是我想知道如何在使用时在anotherF()内部模拟myFunction()调用? 问题答案: 您可以稍微重构一下模块。像这样。

  • 我正在尝试测试一个使用pg模块查询数据库的函数,这是我的使用方法: 通常,我会存根这样的函数(这里db.saveUser是一个假函数,但它确实被正确存根): 然而,这在pg模块上不起作用,我尝试对构造函数,Pool,.connect,.release甚至整个模块进行存根,但由于某种原因似乎没有任何工作。 PS:我还尝试将所有变量的const改为var,因为我认为这是原因,结果也是一样的。我还尝试了

  • 如果我已经通过< code > var a = sinon . createstuinstance(my contractor)创建了一个实例。 如何替换其中一个存根函数,如 。 我这样做的主要原因是想实现这个提到的多个回调解决方法

  • 问题内容: 我需要测试一个函数,该函数需要使用urllib.urlopen(它也使用urllib.urlencode)来查询外部服务器上的页面。服务器可能已关闭,页面可能已更改;我不能依靠它进行测试。 控制urllib.urlopen返回的最佳方法是什么? 问题答案: 另一个简单的方法是让您的测试覆盖urllib的功能。例如,如果您的模块具有 您可以这样定义测试: 然后,当您的测试调用中的函数时,

  • 我想将导入的模块替换为存根,以便只对主模块进行单元测试。我试过用西农。但是它似乎并没有达到我期望的效果,因为我在运行测试时不断遇到错误。 这是我的主要模块。 这是我的测试。 我是不是做错了什么?任何帮助将不胜感激。