我正试图用Midje单独测试我的路由。对于一些访问数据库的路由,我可以使用(provided ...)将路由与真正的db调用隔离开来。我已经介绍了一个用于身份验证的朋友,并且我无法伪造对凭证函数的调用。
我的凭据函数看起来如下(它是这样实现的,因为我还不希望它被调用):
(defn cred-fn
[creds]
(println (str "hey look I got called with " creds))
(throw (Exception.)))然后,用于路由的中间件如下所示:
(def app
(-> app-routes
(wrap-json-body {:keywords? true :bigdecimals? true})
wrap-json-response
(wrap-defaults defaults)
(friend/authenticate
{:unauthorized-handler json-auth/login-failed
:workflows [(json-auth/json-login
:login-uri "/login"
:login-failure-handler json-auth/login-failed
:credential-fn auth/cred-fn)]})
(ring-session/wrap-session)))我也尝试过没有使用auth工作流,路由的实现看起来几乎是一样的,如果它有帮助的话,我可以添加它,但是我得到了相同的结果。
然后,我的测试看起来如下(使用环模拟):
(defn post [url body]
(-> (mock/request :post url body)
(mock/content-type "application/json")
app))
(fact "login with incorrect username and password returns unauthenticated"
(:status (post "/login" invalid-auth-account-json)) => 401
(provided
(auth/cred-fn anything) => nil))
(fact "login with correct username and password returns success"
(:status (post "/login" auth-account-json)) => 200
(provided
(auth/cred-fn anything) => {:identity "root"}))然后,我得到以下运行测试的输出:
hey look I got called with {:password "admin_password", :username "not-a-user"}
FAIL at (handler.clj:66)
These calls were not made the right number of times:
(auth/cred-fn anything) [expected at least once, actually never called]
FAIL "routes - authenticated routes - login with incorrect username and password returns unauthenticated" at (handler.clj:64)
Expected: 401
Actual: java.lang.Exception
clojure_api_seed.authentication$cred_fn.invoke(authentication.clj:23)
hey look I got called with {:password "admin_password", :username "root"}
FAIL at (handler.clj:70)
These calls were not made the right number of times:
(auth/cred-fn anything) [expected at least once, actually never called]
FAIL "routes - authenticated routes - login with correct username and password returns success" at (handler.clj:68)
Expected: 200
Actual: java.lang.Exception
clojure_api_seed.authentication$cred_fn.invoke(authentication.clj:23)因此,从我所看到的情况来看,所提供的语句没有生效,我也不知道为什么。有什么想法吗?
发布于 2015-05-02 23:10:46
我最近遇到了一个类似的问题,经过一番调查,我想我理解了为什么会发生这种情况。让我们看看auth/cred-fn的绑定是如何随时间变化的。
(clojure.pprint/pprint (macroexpand '(defn cred-fn
[creds]
(println (str "hey look I got called with " creds))
(throw (Exception.)))))
(def
cred-fn
(clojure.core/fn
([creds]
(println (str "hey look I got called with " creds))
(throw (Exception.)))))如上文所示,defn宏在当前命名空间中实习生符号cred-fn,并将其绑定到引用虚拟函数的Var。
(def app
(-> app-routes
(wrap-json-body {:keywords? true :bigdecimals? true})
wrap-json-response
(wrap-defaults defaults)
(friend/authenticate
{:unauthorized-handler json-auth/login-failed
:workflows [(json-auth/json-login
:login-uri "/login"
:login-failure-handler json-auth/login-failed
:credential-fn auth/cred-fn)]})
(ring-session/wrap-session)))这是最重要的部分。在编译时,我们通过一系列函数线程app-routes。其中一个函数是friend/authenticate,它使用带有键:workflows的映射。:workflows的值是一个向量,其中填充了对json-auth/json-login的调用结果,后者接收auth/credential-fn作为参数。记住,我们在一个def中,所以这一切都是在编译时发生的。我们在auth命名空间中查找符号cred-fn,并传入符号绑定到的Var。在这一点上,这仍然是虚拟实现。想必,json-auth/json-login捕获这个实现并设置一个请求处理程序来调用它。
(fact "login with incorrect username and password returns unauthenticated"
(:status (post "/login" invalid-auth-account-json)) => 401
(provided
(auth/cred-fn anything) => nil))现在我们在运行时。在我们的前提条件下,Midje将符号auth/cred-fn重新绑定到引用模拟的Var。但是,当我们在编译时使用auth/cred-fn d app时,已经捕获了app的值。
那么,你发布的解决方案是怎么做到的呢?(这实际上是我来到尤里卡时刻的线索--谢谢你。)
(defn another-fn []
(println (str "hey look I got called"))
(throw (Exception.)))
(defn cred-fn [creds]
(another-fn))在你的测试中..。
(fact "login with incorrect username and password returns unauthenticated"
(:status (post "/login" invalid-auth-account-json)) => 401
(provided
(auth/another-fn) => nil))
(fact "login with correct username and password returns success"
(:status (post "/login" auth-account-json)) => 200
(provided
(auth/another-fn) => {:identity "root"}))这是因为,在编译时,捕获的auth/cred-fn值是一个简单地委托给auth/another-fn的函数。请注意,尚未对auth/another-fn进行评估。现在,在我们的测试中,Midje重新绑定auth/another-fn以引用模拟。然后执行post,在中间的某个地方调用auth/cred-fn。在auth/cred-fn中,我们查找绑定到auth/another-fn (这是我们的模拟)的Var,并调用它。当然,现在的行为和你第一次所期望的完全一样。
这个故事的寓意是,be 小心Clojure中的def
发布于 2014-11-14 15:05:18
我还是不知道为什么会这样,但我有工作要做。如果我将我的credential-fn替换为:
(defn another-fn
[]
(println (str "hey look I got called"))
(throw (Exception.)))
(defn cred-fn
[creds]
(another-fn))然后为测试中的新函数创建一个伪函数,如下所示:
(fact "login with incorrect username and password returns unauthenticated"
(:status (post "/login" invalid-auth-account-json)) => 401
(provided
(auth/another-fn) => nil))
(fact "login with correct username and password returns success"
(:status (post "/login" auth-account-json)) => 200
(provided
(auth/another-fn) => {:identity "root"}))我得到了我期待的结果。cred-fn仍然会被调用,但是another-fn不会因为provided而被调用。
如果有人知道为什么我会有兴趣知道的话。这可能是因为凭证函数被调用的方式?- workflow.clj#L46
https://stackoverflow.com/questions/26925557
复制相似问题