如何在打字稿中使用 sinon 来存根 Express 中间件?

2024-01-03

我正在尝试使用 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(使用前将#替换为@)

如何在打字稿中使用 sinon 来存根 Express 中间件? 的相关文章

随机推荐

  • Powershell 无法正确呈现我的脚本帮助

    我有一个 Powershell 脚本 在它的开头有很大的帮助 可以用Get Help命令 https gist github com MarkKharitonov 91698caf8c695902eacde2b6c7825bf1 https
  • 如何将 FQL 与 php api 结合使用?和访问令牌

    呃 我似乎无法让 fql 工作 一件事 我认为文档很旧 因为我不认为 api 只喜欢数组 反正 user id facebook gt getUser works access token facebook gt getAccessToke
  • 如何可靠地检测文件类型? [复制]

    这个问题在这里已经有答案了 目标 给定文件 确定它是否属于给定类型 XML JSON 属性等 考虑 XML 的情况 在我们遇到这个问题之前 以下示例方法运行良好 try saxReader read f catch DocumentExce
  • 将 python 回调函数传递给 Fortran 子例程的开销是多少?

    我刚刚使用 F2PY 将 Fortran 90 子例程包装到 python 中 这里的微妙之处在于 Fortran 子例程也采用 python 回调函数作为其参数之一 SUBROUTINE f90foo pyfunc a real kind
  • 实体框架返回与数据库查询不同的数据

    我可以查看数据库中的某些数据 它会返回我期望的数据 例如 Call Date To From Phone Number 20 1 2010 00 00 23 59 08923233223 20 1 2010 00 00 23 59 0892
  • 通过电子邮件和密码使用 firebase 注册用户?

    我使用 Firebase 授权创建了注册活动 并尝试注册新用户 但是当我按下注册按钮时 我的代码出现异常 protected void onCreate Bundle savedInstanceState super onCreate sa
  • 在Java中,有没有办法指定一个参数实现两个接口

    我很想做这样的代码 使用 jGraphT interface DirectedGraph
  • IIS Express 不保留会话数据

    我有一个在 IIS Express 服务器下的 Visual Studio 2013 中运行的应用程序 问题是会话数据没有保留在页面之间 并且我发现之前的页面不为空的空对象 如果我编译该应用程序并将其部署在带有 IIS 的 Web 服务器上
  • Meteor js 和多人游戏

    我开始学习 Meteor 我意识到它可能是简单多人游戏的良好解决方案 因为它的反应性 客户端 minimongo 数据库 客户端之间的实时交换是否足够快以交换玩家坐标 或者这是一个糟糕的解决方案 我应该在没有中间数据库的情况下完成它 只需直
  • MySQL 存储函数的正确 if 子句语法是什么?

    我是 MySQL 的新手 所以如果其中一些内容相对初级 我深表歉意 我正在尝试编写一个存储函数来将数字四舍五入到一定数量的有效数字 我有一个理论上应该可以工作的函数 我咨询了另一个有用的 StackOverflow 来确定逻辑 SQL 中四
  • 什么情况下使用八进制?

    我经常看到二进制和十六进制使用 但从未见过八进制 然而 八进制在某些语言中使用时有其自己的约定 即 前导 0 表示八进制基数 什么时候使用八进制 当人们使用八进制或八进制更容易推理时 有哪些典型情况 或者这只是一个品味问题 当一个字中的位数
  • 多对多关系中的删除不对称?

    我有两个模型 产品和类别 以及一个用于多对多关系的连接表 类别 假设我有两个对象 产品和类别 它们是上述对象的实例 products Product new category Category new product categories
  • 校验和与“git svn clone”不匹配后如何恢复?

    作为我们迁移计划的一部分 我正在将 SVN 存储库克隆到 git 我一路上遇到了各种障碍 迫使我继续克隆git svn fetch命令 最近的失败我不知道如何解决 git svn fetch Checksum mismatch dc tru
  • UIScrollView不滚动

    我有一个 UIScrollView 根本不滚动 如果我启用弹跳 我可以滚动到足够远的距离以查看视图之外的内容 但当我释放时它会立即回到原点 我已打开寻呼 但如果将其关闭 则会出现相同的行为 我已关闭自动布局 在 IB 中 scrollVie
  • 在 JavaScript 中检查字符串是否包含数组的任何元素

    如何检查字符串是否包含数组的任何元素 如果元素有一些字符串 我想过滤一些数组 请看下面的代码 var arr banana monkey banana apple kiwi orange function checker value var
  • Angular / Electron 未启动

    我使用 Angular CLI 创建了 Angular 10 项目 接下来 我安装了 Electron 并完成了以下操作 将 src index html 基础更改为本地安装的 Electron 但是当运行我的代码时 它显示有一些错误 我该
  • Angular 动态 formControlName 使用 fromGroup 生成

    我创建了一个由 JSON 数组组成的表单 根据该表单 我生成 Validation formControlName 并通过 formGroup 生成输出 this ELEMENT DATA UPDATE first name abc las
  • 警告:发生 HTML 1300 导航?

    我已加载我的网站微软边缘版本 25 10586 0 0 和智能屏幕告诉我该网站可能是假的 此警告是该网站上的新警告 控制台日志显示 HTML1300 Navigation occured example com example com 是我
  • 如何调试在 Windows CE 6 的 .NET CF 3.5 WinForms 应用程序中调用 Application.Exit() 后发生的致命错误?

    我正在将 NET CF 1 0 WinForms 应用程序 适用于旧版本的 Windows CE 移植到 NET CF 3 5 适用于 Windows CE 6 问题是 在调用 Application Exit 几秒钟后 我会看到一个 致命
  • 如何在打字稿中使用 sinon 来存根 Express 中间件?

    我正在尝试使用 typescript mocha sinon 和 chai http 为我的 Express 路由器编写集成测试 该路由器使用我编写的自定义中间件 用于检查标头中的 JWT 理想情况下 我想存根我的authMiddlewar