Clojure 使用redefs fn无法从do seq获取绑定?
有些基本的东西我不明白。我希望下面的测试能通过。但是第二个测试用例“staging”/“staging”失败。就好像redefs fn无法通过测试用例实例一样。但是日志显示一切正常。这令人困惑Clojure 使用redefs fn无法从do seq获取绑定?,clojure,Clojure,有些基本的东西我不明白。我希望下面的测试能通过。但是第二个测试用例“staging”/“staging”失败。就好像redefs fn无法通过测试用例实例一样。但是日志显示一切正常。这令人困惑 (deftest test-bad-derive-s3-environment (testing "variants of props environments" (doseq [test-case [{:env "qa1" :expect "qa1"}
(deftest test-bad-derive-s3-environment
(testing "variants of props environments"
(doseq [test-case [{:env "qa1" :expect "qa1"}
{:env "dev" :expect "qa1"}
{:env "staging" :expect "staging"}]]
(log/infof "test-case %s" test-case)
(with-redefs-fn {#'config/environment (fn [] (:env test-case))}
(let [actual (fs/derive-s3-environment (config/environment))
_ (log/infof "within redefs :env %s :expect %s" (:env test-case) (:expect test-case))]
#(is (= actual (:expect test-case))))))))
...
lein test com.climate.test.mapbook.filestore
2016-05-03 16:16:29,353 INFO filestore:288 - test-case {:env "qa1", :expect "qa1"}
2016-05-03 16:16:29,355 INFO EnvConfig:98 - Loading config properties from /export/disk0/wb/etc/env.properties
2016-05-03 16:16:29,357 INFO EnvConfig:98 - Loading config properties from /export/disk0/wb/etc/local.properties
2016-05-03 16:16:29,358 INFO filestore:288 - within redefs :env qa1 :expect qa1
2016-05-03 16:16:29,359 INFO filestore:288 - test-case {:env "staging", :expect "staging"}
2016-05-03 16:16:29,359 INFO filestore:288 - within redefs :env staging :expect staging
lein test :only com.climate.test.mapbook.filestore/test-bad-derive-s3-environment
FAIL in (test-bad-derive-s3-environment) (filestore.clj:29)
variants of props environments
expected: (= actual (:expect test-case))
actual: (not (= "qa1" "staging"))
2016-05-03 16:16:29,364 INFO filestore:288 - test-case {:env "dev", :expect "qa1"}
2016-05-03 16:16:29,364 INFO filestore:288 - within redefs :env dev :expect qa1
为什么my with redefs fn无法根据当前测试用例重新定义配置/环境功能?首先,请注意,您的最终测试实例有一个
:expect
的“qa1”
——与第一个测试实例相同——因此,如果代码按照您的预期工作,它实际上应该失败;它的通过与第二个实例的失败是同一问题的征兆
现在,解决方案有两个选项:
与redefs一起使用,而不是将与redefs一起使用fn
:
(with-redefs [config/environment (fn [] (:env test-case))]
…)
大多数时候这就是你想做的事情,你可以考虑用ReFDES FN<代码> <代码>是代码后面的一个实现细节,用ReDefs——尽管严格地说,它本身也有一些实用性,因为它可以重新定义动态构建的VARS集合。
将与redefs fn一起使用,但将内部let
表单移动到匿名函数中:
(with-redefs-fn {…}
#(let […]
(is …)))
最后,这些工作的原因和问题文本中的版本不:
with redefs fn
是一个函数,因此在运行时,它的参数将在实际调用之前进行计算,并传递运行时值。特别是,作为第二个参数传入的let
表达式将在重新定义之前进行求值,因此被称为实际值的本地表达式将在重新定义之前获得求值(配置/环境)
的结果作为其值,该值将安装在let
主体中创建的匿名闭包中。然而,当重新定义到位时,将调用该闭包,因此它将从重新定义之前获取其“实际”值的概念,并将其与重新定义后设定的期望值进行比较,从而得出观察到的行为
在闭包内移动let
,就像上面的第二种方法一样,修复了这个不匹配的问题–在重新定义到位的情况下计算let
local的值,一切正常。将与redefs一起使用的第一种方法扩展到第二种方法
日志打印输出很好,因为它们只与doseq
本地相关,从不检查任何变量。如果他们这样做了,他们只会看到预先重新定义的值。我现在正努力理解redefs fn的效用。with redefs的工作原理与champ类似。with redefs fn
是一个实现细节–它存在并且是公共的,因此with redefs
可以在其扩展中使用它。用户代码通常不应该直接调用它。也许我应该在回答中提到这一点!事实上,我收回这句话。大多数情况下,使用redefs的更方便,但是使用redefs的fn
允许重新定义动态创建的变量集合,因此它在某些场景中可能很有用。