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后使用读取器宏:
仍出现相同的类型转换错误,JWT验证问题未解决。(:require [app.model.user.pathom :refer [jwt-secret]]) (with-redefs [#'jwt-secret test-jwt-secret] (f))
环境
- Clojure 1.11
- Pathom 3
- buddy-sign(JWT处理库)
解决方案
核心问题分析
问题根源主要有两个:
- 重定义对象错误:测试命名空间中
refer的jwt-secret是原始Var的别名,对别名执行with-redefs只会修改测试命名空间的局部引用,不会影响app.model.user.pathom中被generate-token使用的原始Var。 - 常量内联干扰:若
jwt-secret被标记为^:const,Clojure会在编译阶段将其值内联到generate-token中,导致运行时的with-redefs无法覆盖。
具体解决步骤
直接重定义原始命名空间的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引用)。确保Var未被标记为常量
检查app.model.user.pathom中jwt-secret的定义,移除^:const标记,避免编译期内联:;; 正确定义,无^:const (def jwt-secret "production-secret") ;; 错误定义,会导致内联失效 ; (def ^:const jwt-secret "production-secret")处理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
相关产品推荐
相关产品推荐

