使用 rewire 存根一个独立的 module.exports 函数

Stub a standalone module.exports function using rewire

我正在尝试 stub module.exports 函数。但是我有点麻烦。我给你一个情况的sudo代码。

MyController.js

const sendOTPOnPhone = rewire('../../src/services/OtpService/sendOTPOnPhone')

module.exports = async function(req, res) {
         const { error, data } = await sendOTPOnPhone(req.query.phone) //this is I want to stub
         if(error)
           return return res.send(error)
         return res.send(data)
}

sendOTPService.js

module.exports = async function(phone) {
               const result = await fetch(`external-api-call`)
               if(result.status !== 'success')
                  return {
                          error: "Failed to send OTP!",
                          data: null
                  }
               return {
                      error: null,
                      data: result
               }
}

sendOTPTest.js

const expect = require('chai').expect
const request = require('supertest')
const sinon = require('sinon')
const rewire = require('rewire')
const sendOTPOnPhone = rewire('../../src/services/OtpService/sendOTPOnPhone')

const app = require('../../src/app')

describe('GET /api/v1/auth/otp/generate', function () {
    it('should generate OTP', async () => {
        let stub = sinon.stub().returns({
            error: null,
            data: "OTP sent"
        })
        sendOTPOnPhone.__set__('sendOTPOnPhone', stub)
        const result = await request(app)
            .get('/api/v1/auth/otp/generate?phone=8576863491')
            .set('Accept', 'application/json')
            .expect('Content-Type', /json/)
            .expect(200)
        expect(stub.calledOnce).to.be.true
        console.log(result.body)
        // expect(result).to.equal('promise resolved'); 
    })
})

以上测试失败,未调用存根。我不知道我错过了什么?如果我在我的 sendOTPService 中这样做:

const sendOTP = async function() {}
module.exports = {
  sendOTP
}

这在控制器中。

const { error, data } = sendOTPOnPhone.sendOTPOnPhone(req.query.phone)

有效。

但是我像这样导入它 const {sendOTPOnPhone } = require('../sendOTPService') 它不起作用。

我知道破坏会更改对象的引用。
有人可以建议解决方法吗?
是否可以使用 rewire 实现此目的?或者可以用 proxyquire 来完成。
有人可以建议吗?

这是使用 proxyquire, you should use Globally override require 的集成测试解决方案。

app.js:

const express = require('express');
const controller = require('./controller');

const app = express();
app.get('/api/v1/auth/otp/generate', controller);

module.exports = app;

controller.js:

let sendOTPOnPhone = require('./sendOTPOnPhone');

module.exports = async function(req, res) {
  const { error, data } = await sendOTPOnPhone(req.query.phone);
  if (error) return res.send(error);
  return res.send(data);
};

sendOTPOnPhone.js:

module.exports = async function(phone) {
  const result = await fetch(`external-api-call`);
  if (result.status !== 'success')
    return {
      error: 'Failed to send OTP!',
      data: null,
    };
  return {
    error: null,
    data: result,
  };
};

sendOTP.test.js:

const request = require('supertest');
const sinon = require('sinon');
const proxyquire = require('proxyquire');

describe('GET /api/v1/auth/otp/generate', function() {
  it('should generate OTP', async () => {
    let stub = sinon.stub().resolves({
      error: null,
      data: { message: 'OTP sent' },
    });
    stub['@global'] = true;
    const app = proxyquire('./app', {
      './sendOTPOnPhone': stub,
    });
    const result = await request(app)
      .get('/api/v1/auth/otp/generate?phone=8576863491')
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200);
    sinon.assert.calledOnce(stub);
    console.log(result.body);
  });
});

集成测试结果与覆盖率报告:

  GET /api/v1/auth/otp/generate
{ message: 'OTP sent' }
    ✓ should generate OTP (2373ms)


  1 passing (2s)

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   68.75 |       25 |      50 |   73.33 |                   
 app.js            |     100 |      100 |     100 |     100 |                   
 controller.js     |   83.33 |       50 |     100 |     100 | 5                 
 sendOTPOnPhone.js |      20 |        0 |       0 |      20 | 2-4,8             
-------------------|---------|----------|---------|---------|-------------------

源代码:https://github.com/mrdulin/expressjs-research/tree/master/src/Whosebug/60599945

我已经回答了一个类似的问题stub SMS otp method(没有使用外部依赖,比如proxyquire)

基本上,问题出在导出上。将您的 sendOtp 方法移动到通用位置,例如用户模型或架构。导入模型,存根其功能。它应该可以正常工作。

您正在导入名为 sendOtp 的导入 属性 而不是原始函数。