如何断言 Express app.use 是用中间件函数调用的? (摩卡)
How to assert that Express app.use is called with middleware function? (Mocha)
我需要测试 app.use 是否被中间件调用。
app.use
使用 returns 函数调用,我无法对其进行测试。
- 应用-factory.js
const express = require('express')
const app = express()
const csurf = require('csurf')
const cookieParser = require('cookie-parser')
class AppFactory {
createApp () {
app.use(csurf({ cookie: true }))
app.use(cookieParser())
return app
}
}
module.exports = {
AppFactory: AppFactory,
app: app,
csurf: csurf
}
- 应用-factory.test.js
const chai = require('chai')
const assert = chai.assert
const rewire = require('rewire')
const appFactoryRewire = rewire('../server/app-factory.js')
const sinon = require('sinon')
const appFactory = require('../server/app-factory')
describe('csurf middleware', () => {
const rewiredCsurf = appFactoryRewire.__get__('csurf')
it('should exist', () => {
assert.exists(rewiredCsurf)
})
it('should be a function', () => {
assert.isFunction(rewiredCsurf)
})
it('should be equal csurf module', () => {
assert.strictEqual(rewiredCsurf, require('csurf'))
})
it('should be called once as app.use arg', () => {
const csurf = appFactory.csurf
const appUseSpy = sinon.spy(appFactory.app, 'use')
const appInstance = new appFactory.AppFactory()
appInstance.createApp()
sinon.assert.calledWith(appUseSpy, csurf({ cookie: true }))
})
})
- 失败的测试输出:
1) csurf middleware
should be called once as app.use arg:
AssertError: expected use to be called with arguments
Call 1:
function cookieParser() {} function csrf() {}
Call 2:
function csrf() {}
at Object.fail (node_modules/sinon/lib/sinon/assert.js:107:21)
at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:16)
at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:92:13)
at Context.<anonymous> (test/app.test.js:45:18)
at processImmediate (internal/timers.js:461:21)
如果我用 app.use('/passport', routes)
之类的字符串调用 app.use
并执行 sinon.assert.calledWith(appUseSpy, '/passport)
它会起作用。
如何断言 app.use
是用 csrf({ cookie: true })
调用的?
单元测试解决方案:
app-factory.js
:
const express = require('express');
const app = express();
const csurf = require('csurf');
const cookieParser = require('cookie-parser');
class AppFactory {
createApp() {
app.use(csurf({ cookie: true }));
app.use(cookieParser());
return app;
}
}
module.exports = {
AppFactory: AppFactory,
app: app,
};
app-factory.test.js
:
const chai = require('chai');
const rewire = require('rewire');
const sinon = require('sinon');
const { expect } = chai;
describe('csurf middleware', () => {
it('should be called once as app.use arg', (done) => {
const appFactory = rewire('./app-factory');
const mCsurfRequestHandler = sinon.stub();
const mCsurf = sinon.stub().returns(mCsurfRequestHandler);
const mCookieParserRequestHandler = sinon.stub();
const mCookieParser = sinon.stub().returns(mCookieParserRequestHandler);
appFactory.__with__({
csurf: mCsurf,
cookieParser: mCookieParser,
})(() => {
const appUseStub = sinon.stub(appFactory.app, 'use');
const appInstance = new appFactory.AppFactory();
const actual = appInstance.createApp();
expect(actual).to.be.equal(appFactory.app);
sinon.assert.calledWithExactly(mCsurf, { cookie: true });
sinon.assert.calledOnce(mCookieParser);
sinon.assert.calledWith(appUseStub, mCsurfRequestHandler);
sinon.assert.calledWith(appUseStub, mCookieParserRequestHandler);
done();
});
});
});
单元测试结果:
csurf middleware
✓ should be called once as app.use arg (214ms)
1 passing (223ms)
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
app-factory.js | 100 | 100 | 100 | 100 |
----------------|---------|----------|---------|---------|-------------------
可以创建一个辅助函数来将函数参数作为字符串进行比较:
- 应用-factory.test.js
const chai = require('chai')
const assert = chai.assert
const rewire = require('rewire')
const appFactoryRewire = rewire('../server/app-factory.js')
const sinon = require('sinon')
/**
* Helper: Returns the argument call number with matching args
* If none found, returns undefined
* @param {*} spyFn sinon.Spy function
* @param {*} argFn callback / function param
*/
function assertCalledWithFunctionAsArg (spyFn, argFn) {
const calls = spyFn.getCalls()
const argFnString = argFn.toString()
let foundMatch = false
for (const call in calls) {
const arg = spyFn.getCall(call).args[0]
if (arg.toString() === argFnString) {
// foundCall = spyFn.getCall(call)
foundMatch = true
}
}
assert(foundMatch === true,
'Spy function/method was not called with expected function')
}
describe('csurf middleware', () => {
const rewiredCsurf = appFactoryRewire.__get__('csurf')
it('should exist', () => {
assert.exists(rewiredCsurf)
})
it('should be a function', () => {
assert.isFunction(rewiredCsurf)
})
it('should be equal csurf module', () => {
assert.strictEqual(rewiredCsurf, require('csurf'))
})
it('should be called once as app.use arg', () => {
const csurf = require('csurf')
const app = appFactoryRewire.__get__('app')
const AppFactory = appFactoryRewire.__get__('AppFactory')
const appUseSpy = sinon.spy(app, 'use')
const appInstance = new AppFactory()
appInstance.createApp()
assertCalledWithFunctionAsArg(appUseSpy, csurf({ cookies: true }))
sinon.restore()
})
})
我需要测试 app.use 是否被中间件调用。
app.use
使用 returns 函数调用,我无法对其进行测试。
- 应用-factory.js
const express = require('express')
const app = express()
const csurf = require('csurf')
const cookieParser = require('cookie-parser')
class AppFactory {
createApp () {
app.use(csurf({ cookie: true }))
app.use(cookieParser())
return app
}
}
module.exports = {
AppFactory: AppFactory,
app: app,
csurf: csurf
}
- 应用-factory.test.js
const chai = require('chai')
const assert = chai.assert
const rewire = require('rewire')
const appFactoryRewire = rewire('../server/app-factory.js')
const sinon = require('sinon')
const appFactory = require('../server/app-factory')
describe('csurf middleware', () => {
const rewiredCsurf = appFactoryRewire.__get__('csurf')
it('should exist', () => {
assert.exists(rewiredCsurf)
})
it('should be a function', () => {
assert.isFunction(rewiredCsurf)
})
it('should be equal csurf module', () => {
assert.strictEqual(rewiredCsurf, require('csurf'))
})
it('should be called once as app.use arg', () => {
const csurf = appFactory.csurf
const appUseSpy = sinon.spy(appFactory.app, 'use')
const appInstance = new appFactory.AppFactory()
appInstance.createApp()
sinon.assert.calledWith(appUseSpy, csurf({ cookie: true }))
})
})
- 失败的测试输出:
1) csurf middleware
should be called once as app.use arg:
AssertError: expected use to be called with arguments
Call 1:
function cookieParser() {} function csrf() {}
Call 2:
function csrf() {}
at Object.fail (node_modules/sinon/lib/sinon/assert.js:107:21)
at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:16)
at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:92:13)
at Context.<anonymous> (test/app.test.js:45:18)
at processImmediate (internal/timers.js:461:21)
如果我用 app.use('/passport', routes)
之类的字符串调用 app.use
并执行 sinon.assert.calledWith(appUseSpy, '/passport)
它会起作用。
如何断言 app.use
是用 csrf({ cookie: true })
调用的?
单元测试解决方案:
app-factory.js
:
const express = require('express');
const app = express();
const csurf = require('csurf');
const cookieParser = require('cookie-parser');
class AppFactory {
createApp() {
app.use(csurf({ cookie: true }));
app.use(cookieParser());
return app;
}
}
module.exports = {
AppFactory: AppFactory,
app: app,
};
app-factory.test.js
:
const chai = require('chai');
const rewire = require('rewire');
const sinon = require('sinon');
const { expect } = chai;
describe('csurf middleware', () => {
it('should be called once as app.use arg', (done) => {
const appFactory = rewire('./app-factory');
const mCsurfRequestHandler = sinon.stub();
const mCsurf = sinon.stub().returns(mCsurfRequestHandler);
const mCookieParserRequestHandler = sinon.stub();
const mCookieParser = sinon.stub().returns(mCookieParserRequestHandler);
appFactory.__with__({
csurf: mCsurf,
cookieParser: mCookieParser,
})(() => {
const appUseStub = sinon.stub(appFactory.app, 'use');
const appInstance = new appFactory.AppFactory();
const actual = appInstance.createApp();
expect(actual).to.be.equal(appFactory.app);
sinon.assert.calledWithExactly(mCsurf, { cookie: true });
sinon.assert.calledOnce(mCookieParser);
sinon.assert.calledWith(appUseStub, mCsurfRequestHandler);
sinon.assert.calledWith(appUseStub, mCookieParserRequestHandler);
done();
});
});
});
单元测试结果:
csurf middleware
✓ should be called once as app.use arg (214ms)
1 passing (223ms)
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
app-factory.js | 100 | 100 | 100 | 100 |
----------------|---------|----------|---------|---------|-------------------
可以创建一个辅助函数来将函数参数作为字符串进行比较:
- 应用-factory.test.js
const chai = require('chai')
const assert = chai.assert
const rewire = require('rewire')
const appFactoryRewire = rewire('../server/app-factory.js')
const sinon = require('sinon')
/**
* Helper: Returns the argument call number with matching args
* If none found, returns undefined
* @param {*} spyFn sinon.Spy function
* @param {*} argFn callback / function param
*/
function assertCalledWithFunctionAsArg (spyFn, argFn) {
const calls = spyFn.getCalls()
const argFnString = argFn.toString()
let foundMatch = false
for (const call in calls) {
const arg = spyFn.getCall(call).args[0]
if (arg.toString() === argFnString) {
// foundCall = spyFn.getCall(call)
foundMatch = true
}
}
assert(foundMatch === true,
'Spy function/method was not called with expected function')
}
describe('csurf middleware', () => {
const rewiredCsurf = appFactoryRewire.__get__('csurf')
it('should exist', () => {
assert.exists(rewiredCsurf)
})
it('should be a function', () => {
assert.isFunction(rewiredCsurf)
})
it('should be equal csurf module', () => {
assert.strictEqual(rewiredCsurf, require('csurf'))
})
it('should be called once as app.use arg', () => {
const csurf = require('csurf')
const app = appFactoryRewire.__get__('app')
const AppFactory = appFactoryRewire.__get__('AppFactory')
const appUseSpy = sinon.spy(app, 'use')
const appInstance = new AppFactory()
appInstance.createApp()
assertCalledWithFunctionAsArg(appUseSpy, csurf({ cookies: true }))
sinon.restore()
})
})