【问题标题】:Why does sinon stub not replacing the actual exports.function为什么 sinon 存根不替换实际的exports.function
【发布时间】:2020-09-07 04:54:40
【问题描述】:

我有一个控制器异步函数,它调用另一个异步导出函数,而不是测试依赖项,我只想测试该依赖项函数的特定结果。但是,当我存根函数时,什么都没有发生,返回结果就好像我从来没有存根函数一样。

exports.getUser = async (req, res) => {
    try {
        let user = null; 

        if(req && req.params.id) {
            const id = parseInt(req.params.id, 10);
            if(isNaN(id)) {
                return res.status(500).json({ message: 'Invalid request.' });
            }

            user = await userService.getUserById(id);

            if(!products) {
                return res.status(404).json({ message: `user does not exist for the given id` });
            }
        } else {
            user = await userService.getUser();
            if(!user || user.length === 0) {
                return res.status(500).json({ message: 'user not available' });
            }
        }
        res.jsonp({user});
    } catch(e) {
        return res.status(500).json({message: e.message});
    }
}

现在我正在尝试对上述函数进行存根。但我的存根不工作。

测试文件:

const expect = require("chai").expect;
const request = require("supertest");
const server = require('../../server');
const sinon = require('sinon');
const userController = require('../../contollers/user');

describe('GET /v1/user', () => {
        let userControllerStub;
        beforeEach(() => {            
            userControllerStub = sinon
                .stub(userController, 'getUser')
                .resolves({getUser: [{ id: 123, name: 'xxxxx' }]});
        })

        afterEach(() => {
            userControllerStub.restore();
        });
        it('Should return list of users', (done) => {
            try {
                request(server).get('/v1/user')
                .end((err, res) => {
                    if (err) {
                        done(err);
                    }
                    console.log('res', res.body);
                    expect(res.statusCode).to.equal(200);

                    //expect(res.body.user).to.have.lengthOf(4); here i am expetcing stub should return the value
                    done();
                });
            } catch (err) {
                done(err)
            }

        });
    });

非常感谢任何帮助。

【问题讨论】:

    标签: javascript node.js express sinon supertest


    【解决方案1】:

    基于测试金字塔,我可以回答 2 级。

    1. 上下文单元测试。

    我建议您在进行下一点之前先创建此测试。您需要直接测试才能使用 getUser。当您测试该功能时,您需要存根 userService.getUserById 或 userService.getUser 取决于您的情况。

    例子:

    const sinon = require('sinon');
    
    // Need to load user controller, the focus of the unit test.
    const userController = require('../../controller/user');
    
    // Need to load userServer for stub purpose.
    // Note: I do not know whether this path is correct.
    const userService = require('../../services/user');
    
    
    describe('Controller User', function () {
      describe('getUser', async function () {
        it('with request param id', function () {
          const stubUserServGetUserById = sinon.stub(userService, 'getUserById');
          stubUserServGetUserById.resolves({ user: 'xxx' });
    
          // Prepare the arguments.
          const req = { params: { id: 1 } };
          // Example: fake all resp. (or you can get the real resp)
          const resp = {
            status: sinon.fake(),
            json: sinon.fake(),
            jsonp: sinon.fake(),
          };
    
          // Called getUser directly.
          const result = await userController.getUser(req, resp);
    
          // Example: Expect the result.
          expect(result).to.equal();
          // Expect whether stub get called.
          expect(stubUserServGetUserById.calledOnce).to.equal(true);
          // Also you can validate whether fake function at resp get called if you need.
    
          // Do not forget to restore the stub.
          stubUserServGetUserById.restore();
        });
    
        it ('without request apram id', function () {
          const stubUserServGetUser = sinon.stub(userController, 'getUser');
          stubUserServGetUser.resolves({ user: 'xxx' });
    
          // Prepare the arguments.
          const req = { params: {} };
          // Example: fake all resp. (or you can get the real resp)
          const resp = {
            status: sinon.fake(),
            json: sinon.fake(),
            jsonp: sinon.fake(),
          };
    
          // Called getUser directly.
          const result = await userController.getUser(req, resp);
    
          // Example: Expect the result.
          expect(result).to.equal();
          // Expect whether stub get called.
          expect(stubUserServGetUser.calledOnce).to.equal(true);
          // Also you can validate whether fake function at resp get called if you need.
    
          // Do not forget to restore the stub.
          stubUserServGetUser.restore();
        });
      });
    });
    
    
    1. 上下文服务测试。

    这正是您在上面的示例测试文件中尝试做的事情。但是你要知道,测试用户v1服务不仅涉及控制器getUser,还涉及其他控制器,我不知道。在此测试级别上,我建议您设置虚拟用户数据。测试前添加虚拟数据,测试后删除虚拟数据。然后添加验证控制器 getUser 是否被调用。或者,您可以将存根从 userController.getUser 更改为 userService.getUser(因为您知道 getUser 将根据之前的单元测试被调用)。 这里没有样品。对不起。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-09
      • 2018-08-02
      • 2018-11-22
      • 1970-01-01
      • 1970-01-01
      • 2013-01-06
      • 2021-09-10
      • 2019-03-13
      相关资源
      最近更新 更多