javascript - Sinon 存根无法使用 module.exports = { f1, f2}
问题描述
我有这个发送 otp 的文件,如下所示。
OtpService.js
const generateOTP = async function() {
//
}
const verifyOTP = async function() {
//
}
module.exports = {
generateOTP,
verifyOTP
}
下面是使用这些方法的控制器otp.js
const { verifyOTP, generateOTP } = require('../../services/OtpService')
const verify = async function(req, res) {
const {error, data} = await generateOTP(req.query.phone)
}
const send = async function(req, res) {
const {error, data} = await verifyOTP(req.query.phone, req.query.otp)
}
module.exports = {
send,
verify
}
下面是测试文件 otp.test.js
const sinon = require('sinon');
const expect = require('chai').expect
const request = require('supertest')
const OtpService = require('../../src/services/OtpService')
console.log(OtpService)
describe('GET /api/v1/auth/otp', function() {
let server
let stub
const app = require('../../src/app')
stub = sinon.stub(OtpService, 'generateOTP').resolves({
error: null,
data: "OTP Sent"
})
server = request(app)
it('should generate OTP', async () => {
const result = await server
.get('/api/v1/auth/otp/send?phone=7845897889')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
console.log(result.body)
expect(stub.called).to.be.true
expect(result).to.be.a('Object')
});
});
上面不起作用,在控制器中调用时它没有存根generateOTP
and方法。verifyOTP
但是,如果我调用OtpService.generateOTP()
,otp.test.js
那么它在那里工作,但它在控制器中不起作用。
诗乃如何在这里工作?
我在这里很困惑。要求应用程序然后存根是正确的还是先存根然后要求是正确的?
我已经尝试了两种方法,尽管它们都不起作用。我也尝试使用before() and beforeEach()
.
下面是我的文件夹结构。
otp.js
(控制器)在这里controller->AuthController->otp.js
otp.test.js
在这儿test->auth->otp.test.js
OtpService.js
就在里面services
更新
我发现了问题所在。如果我不在控制器中使用破坏功能,一切正常。所以,使用OtpService.generateOTP
作品。
问题在于对象的破坏。
const { verifyOTP, generateOTP } = require('../../services/OtpService')
上面是在存根之前运行的。所以verifyOTP
并且generateOTP
已经参考了这些unstubbed
方法。
我需要一个解决方法。我想使用破坏功能。
解决方案
我使用proxyquire包来存根OtpService
模块。下面的示例是单元测试,但您可以使用这种方式进行集成测试。
例如
otp.js
:
const { verifyOTP, generateOTP } = require('./OtpService');
const verify = async function(req, res) {
return generateOTP(req.query.phone);
};
const send = async function(req, res) {
return verifyOTP(req.query.phone, req.query.otp);
};
module.exports = {
send,
verify,
};
OtpService.js
:
const generateOTP = async function() {
//
};
const verifyOTP = async function() {
//
};
module.exports = {
generateOTP,
verifyOTP,
};
otp.test.js
:
const proxyquire = require('proxyquire');
const sinon = require('sinon');
describe('60704684', () => {
it('should send', async () => {
const otpServiceStub = {
verifyOTP: sinon.stub().resolves({ error: null, data: 'fake data' }),
generateOTP: sinon.stub(),
};
const { send } = proxyquire('./otp', {
'./OtpService': otpServiceStub,
});
const mReq = { query: { phone: '123', otp: 'otp' } };
const mRes = {};
await send(mReq, mRes);
sinon.assert.calledWithExactly(otpServiceStub.verifyOTP, '123', 'otp');
});
it('should verfiy', async () => {
const otpServiceStub = {
verifyOTP: sinon.stub(),
generateOTP: sinon.stub().resolves({ error: null, data: 'fake data' }),
};
const { verify } = proxyquire('./otp', {
'./OtpService': otpServiceStub,
});
const mReq = { query: { phone: '123' } };
const mRes = {};
await verify(mReq, mRes);
sinon.assert.calledWithExactly(otpServiceStub.generateOTP, '123');
});
});
带有覆盖率报告的单元测试结果:
60704684
✓ should send (1744ms)
✓ should verfiy
2 passing (2s)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 50 | 100 |
OtpService.js | 100 | 100 | 0 | 100 |
otp.js | 100 | 100 | 100 | 100 |
---------------|---------|----------|---------|---------|-------------------
源代码:https ://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/60704684
推荐阅读
- python - 在 postgreSQL 中找不到 uninstall.dat 文件
- java - Maven 发布插件 SSL 问题
- android - 安卓麦克风通过蓝牙连接到手机
- c# - 从服务器外部访问网站时,ASP.Net PageLoad 和控制事件触发两次
- reactjs - 未捕获的 SyntaxError:标识符“套接字”已在客户端文件中声明
- asp.net-core - 在 netcore2.1 中生成 HMAC SHA3-512
- html - 无法使用 .close() 关闭 ngb-datepicker(.close() 不是函数)
- combobox - 如何将样式应用于 XPages 中的层次组合框
- java - 进入子目录时 JSF WebContent 呈现方法不起作用
- python - 创建包含另一个数据框的列名和相应值的 df