我正在尝试使用 typescript、mocha、sinon 和 chai-http 为我的 Express 路由器编写集成测试。该路由器使用我编写的自定义中间件,用于检查标头中的 JWT。
理想情况下,我想存根我的authMiddleware
这样我就可以控制它的行为,而无需为每个测试用例实际提供有效/无效的 JWT。
当我尝试存根时authMiddleware
在我的测试中,我意识到表达app
使用实际实现authMiddleware
而不是嘲笑一个人。
我尝试过导入app
嘲笑之后authMiddleware
使用打字稿的动态导入,但它也不起作用。
authMiddleware.ts
import { Request, Response, NextFunction } from 'express';
export default class AuthMiddleware {
verifyToken(req: Request, res: Response, next: NextFunction) :void {
console.log('Actual implemetation of verifyToken is called!');
// verify token
next();
}
}
主题路由器.ts
import express from'express';
import AuthMiddleware from '../middleware/authMiddleware';
import * as subjectController from '../controller/subjectController';
const router = express.Router();
const authMiddleware = new AuthMiddleware();
router.post('/', authMiddleware.verifyToken, subjectController.createSubject);
export default router;
app.ts
import express from 'express';
import subjectRoute from './route/subjectRoute';
// Initilize express app
const app = express();
app.set("port", 3000);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Routers
app.use('/user', userRoute);
app.use('/subject', subjectRoute);
export default app;
主题测试.ts
import app from '../../src/app';
import AuthMiddleware from '../../../src/middleware/AuthMiddleware';
describe('Subject', () => {
let app;
beforeEach(async () => {
sinon.stub(AuthMiddleware.prototype, 'verifyToken').callsFake((req: Request, res: Response, next: NextFunction): void => {
console.log('Fake verifyToken is called!');
// THIS IS NEVER CALLED IN TESTS...
});
app = (await import('../../../src/app')).default;
});
it('should throw 403 when jwt is missing in header', (done) => {
request(app)
.post(/subject)
.end((err, res) => {
expect(res).has.status(403);
done();
});
});
});
当我运行上面的测试时,我看到了那个模拟authMiddleware
不被调用。app
在测试中使用真实的实现authMiddleware
object.
有没有办法存根快速中间件并将其显式传递给应用程序?
我刚刚解释了发生的事情这个回应 https://stackoverflow.com/questions/62626143/why-is-my-sinon-stub-acting-like-its-calling-the-real-function/62682486#62682486,但是仅给出解决方法。
经过一番思考,我相信克服这个问题的最佳方法是从模块中删除全局状态,并将整个初始化代码捕获到显式调用的函数(或类,如果您愿意)中,这样您就可以为每个测试创建服务器。即,将您的架构更改为:
// router.ts
export function createRouter() {
/// ...
router.post('/', authMiddleware.verifyToken, subjectController.createSubject);
return router;
}
// app.ts
import { createRouter} from "./router.js"
export function createApp() {
///same code as currently, but in function
app.use('/subject', createRouter());
}
现在,您可以在每个设置回调中创建新的“应用程序”:
// test.ts
beforeEach(async () => {
sinon.stub(AuthMiddleware.prototype, 'verifyToken').callsFake((req: Request, res: Response, next: NextFunction): void => {
...
});
app = (await import('../../../src/app')).createApp(); // note that we create new app for each test, so you're not polutting global state of app
});
这种方法有很多优点,其中包括:
- 您可以为不同的测试模拟不同的函数;
- 您正在有效地从代码中删除“隐式单例”
存在是您问题的根本原因。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)