我创建了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,但仅当我将其放在文件的顶部时,它仍然有效。
解决这个问题的方法是什么,而不是把存根放在测试文件的顶部?谢谢!
问题中的解决方案有点受限,因为模拟已经污染了整个测试套件。
我最后这样做了,逻辑很简单,我们仍然需要先模拟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的功能。例如,如果您的模块具有 您可以这样定义测试: 然后,当您的测试调用中的函数时,
我想将导入的模块替换为存根,以便只对主模块进行单元测试。我试过用西农。但是它似乎并没有达到我期望的效果,因为我在运行测试时不断遇到错误。 这是我的主要模块。 这是我的测试。 我是不是做错了什么?任何帮助将不胜感激。