You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sinon模拟fastify-auth插件返回值失败问题排查

Sinon模拟fastify-auth验证函数失效的解决方法

问题原因

你的模拟代码不生效,核心是模块加载顺序和函数引用捕获导致的:

  • 测试代码中,你先导入了verifyGipToken模块,再导入fastify路由/插件,但此时gip-bearer-auth-plugin已经提前加载了原始的verifyGipToken函数引用,后续的stub无法覆盖已经被插件捕获的函数。
  • Fastify注册插件时,fastify.auth([verifyGipToken])会把当时的函数引用存入钩子,后续修改模块导出的函数不会影响这个已存储的引用。

解决方案

1. 调整模块导入顺序,先Stub再加载依赖模块

在测试中,必须先完成verifyGipToken的Stub,再导入任何依赖该函数的模块(比如fastify路由、认证插件),确保这些模块拿到的是Stub后的函数引用。

修改后的测试文件示例:

// test.js
const t = require('tap')
const sinon = require('sinon')

// 1. 先导入要Stub的模块
const verifyGipTokenModule = require('/path/to/verifyGipToken')
const sandbox = sinon.createSandbox()

t.beforeEach(async t => {
  // 2. 完成Stub
  sandbox.stub(verifyGipTokenModule, 'verifyGipToken').callsFake(async req => {
    console.log('verifyGipToken stub called')
    return true
  })
  
  // 3. 再导入Fastify应用/路由模块,确保Stub已生效
  const buildApp = require('/path/to/your-fastify-app')
  t.context.app = await buildApp() // 假设你的应用导出的是创建实例的函数
})

t.afterEach(async t => {
  sandbox.restore()
})

t.test('POST /v2/test 验证通过', async t => {
  // 4. 发送测试请求
  const response = await t.context.app.inject({
    method: 'POST',
    url: '/v2/test',
    headers: {
      // 可选:添加必要的请求头,比如Authorization
    }
  })

  t.equal(response.statusCode, 200, '请求应成功返回')
})

2. 确保Fastify应用的构建逻辑正确

如果你的Fastify应用是通过导出一个构建函数(而非直接创建实例),那么每次测试前构建实例时,都会使用最新的模块导出(也就是Stub后的函数)。比如调整你的应用入口:

// app.js(假设你的应用入口)
const fastify = require('fastify')

module.exports = async function buildApp() {
  const app = fastify()
  await app.register(require('./routes')) // 这里会加载路由和认证插件
  return app
}

备选方案:使用proxyquire替换模块

如果调整导入顺序不方便,可以用proxyquire直接在导入模块时替换verifyGipToken的实现:

// test.js
const t = require('tap')
const sinon = require('sinon')
const proxyquire = require('proxyquire')

t.test('test case', async t => {
  const verifyStub = sinon.stub().resolves(true)
  
  // 用proxyquire导入路由模块,替换verifyGipToken
  const buildApp = proxyquire('/path/to/your-fastify-app', {
    './share/helpers/verifyGipToken': {
      verifyGipToken: verifyStub
    }
  })

  const app = await buildApp()
  const response = await app.inject({
    method: 'POST',
    url: '/v2/test'
  })

  t.ok(verifyStub.called, '验证函数应被调用')
  t.equal(response.statusCode, 200)
})

关键注意点

  • 必须保证Stub操作在任何依赖该函数的模块导入之前执行,Node.js的模块缓存机制会记住第一次导入的模块导出,后续导入不会重新加载。
  • Fastify的钩子会捕获注册时的函数引用,所以要确保注册钩子时使用的是Stub后的函数。

内容的提问来源于stack exchange,提问作者Hamza Boularbah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 03:28:23