如何在typescript中使用sinon来存根表示中间件?

如何在typescript中使用sinon来存根表示中间件?,typescript,express,mocha.js,sinon,chai-http,Typescript,Express,Mocha.js,Sinon,Chai Http,我正在尝试使用typescript、mocha、sinon和chai http为我的express路由器编写一个集成测试。这个路由器使用我编写的自定义中间件,它检查头中的JWT 理想情况下,我希望存根我的authMiddleware,这样我就可以控制它的行为,而不必为每个测试用例提供有效/无效的JWT 当我在测试中尝试存根authMiddleware时,我意识到expressapp使用了authMiddleware的实际实现,而不是模拟的实现 在模拟authMiddleware之后,我尝试使用t

我正在尝试使用typescript、mocha、sinon和chai http为我的express路由器编写一个集成测试。这个路由器使用我编写的自定义中间件,它检查头中的JWT

理想情况下,我希望存根我的
authMiddleware
,这样我就可以控制它的行为,而不必为每个测试用例提供有效/无效的JWT

当我在测试中尝试存根
authMiddleware
时,我意识到express
app
使用了
authMiddleware
的实际实现,而不是模拟的实现

在模拟
authMiddleware
之后,我尝试使用typescript的动态导入导入
app
,但也不起作用

authMiddleware.ts
import{Request,Response,NextFunction}来自“express”;
导出默认类验证中间件{
verifyToken(请求:请求,响应:响应,下一步:下一步功能):无效{
log('verifyToken的实际实现被调用!');
//验证令牌
next();
}

}
我刚刚解释了在中发生的事情,但只给出了解决方法

经过几番思考,我相信克服这一问题的最佳方法是从模块中删除全局状态,并将整个初始化代码捕获到显式调用的函数(或类,如果您愿意)中,以便为每个测试创建服务器。即,将您的体系结构更改为:

// 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
});
除其他外,这种方法有许多优点:

  • 您可以为不同的测试模拟不同的函数
  • 您正在有效地从代码中删除“隐式单例” 存在是你问题的根本原因

对于这个问题,是否有任何新的解决方案不涉及中断对测试代码的更改?