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

Clojure测试fixture中无法重定义其他命名空间的JWT密钥问题

在Clojure测试Fixture中正确重定义跨命名空间Var的方法

当前配置

在app.model.user.pathom命名空间中定义JWT密钥:

;; app.model.user.pathom 命名空间
(def jwt-secret "production-secret")

测试命名空间中的Fixture尝试替换为测试密钥:

;; 测试命名空间 app.model.user.pathom-test
(ns app.model.user.pathom-test
  (:require [app.model.user.pathom :refer [jwt-secret]]))

(def test-jwt-secret "test-secret")

(defn with-jwt-secret [f]
  (with-redefs [jwt-secret test-jwt-secret]
    (f)))

(use-fixtures :each (join-fixtures [db-cleanup-fixture
                                  email-fixture
                                  with-fixed-time
                                  with-jwt-secret]))

密钥在generate-token函数中被使用:

(defn generate-token [user-id client-type]
  (jwt/sign claims jwt-secret {:alg :hs256}))

问题

重定义未生效,测试仍使用生产环境密钥,导致JWT验证失败:

Caused by: clojure.lang.ExceptionInfo: Message seems corrupt or manipulated

手动将测试环境密钥改为生产值时测试可正常通过。

已尝试方案

  • 使用全限定命名空间:
    (with-redefs [app.model.user.pathom/jwt-secret test-jwt-secret]
      (f))
    
    未解决问题。
  • 使用读取器宏:
    (with-redefs [#'app.model.user.pathom/jwt-secret test-jwt-secret]
      (f))
    
    抛出错误:Caused by: java.lang.ClassCastException: class clojure.lang.Cons cannot be cast to class clojure.lang.Symbol
  • 引用Var后使用读取器宏:
    (:require [app.model.user.pathom :refer [jwt-secret]])
    
    (with-redefs [#'jwt-secret test-jwt-secret]
      (f))
    
    仍出现相同的类型转换错误,JWT验证问题未解决。

环境

  • Clojure 1.11
  • Pathom 3
  • buddy-sign(JWT处理库)

解决方案

核心问题分析

问题根源主要有两个:

  1. 重定义对象错误:测试命名空间中refer的jwt-secret是原始Var的别名,对别名执行with-redefs只会修改测试命名空间的局部引用,不会影响app.model.user.pathom中被generate-token使用的原始Var。
  2. 常量内联干扰:若jwt-secret被标记为^:const,Clojure会在编译阶段将其值内联到generate-token中,导致运行时的with-redefs无法覆盖。

具体解决步骤

  1. 直接重定义原始命名空间的Var
    无需refer目标Var,直接在with-redefs中使用全限定命名空间符号,确保修改的是原始Var:

    ;; 测试命名空间中修改Fixture
    (ns app.model.user.pathom-test
      (:require [app.model.user.pathom])) ; 不需要refer,直接用全限定名
    
    (def test-jwt-secret "test-secret")
    
    (defn with-jwt-secret [f]
      (with-redefs [app.model.user.pathom/jwt-secret test-jwt-secret]
        (f)))
    

    注:with-redefs接受符号作为键,无需添加#'读取器宏;若使用读取器宏需确保语法正确(如#'app.model.user.pathom/jwt-secret是合法的Var引用)。

  2. 确保Var未被标记为常量
    检查app.model.user.pathom中jwt-secret的定义,移除^:const标记,避免编译期内联:

    ;; 正确定义,无^:const
    (def jwt-secret "production-secret")
    
    ;; 错误定义,会导致内联失效
    ; (def ^:const jwt-secret "production-secret")
    
  3. 处理Pathom 3的缓存问题
    若generate-token是Pathom resolver的一部分,Pathom可能在初始化时捕获Var值。需确保在Pathom环境初始化之前执行with-redefs,或在resolver中显式读取Var的当前值(如(var-get #'app.model.user.pathom/jwt-secret))。

验证

修改Fixture后,运行测试时generate-token会读取重定义后的测试密钥,JWT验证即可正常通过。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:39:59