with-redefs-fn无法从do-seq获取绑定?

时间:2016-05-03 22:17:04

标签: clojure

有一些基本的东西,我没有到这里来。我希望以下测试通过。但是第二个测试用例“staging”/“staging”失败了。它好像with-redefs-fn无法通过测试用例实例。但伐木说一切都很好。这很令人困惑。

(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

为什么我的with-redefs-fn无法根据当前的测试用例重新定义配置/环境功能?

1 个答案:

答案 0 :(得分:2)

首先,请注意您的最终测试实例具有:expect "qa1" - 与第一个测试实例相同 - 因此如果代码按预期工作,它实际上应该失败;它的传递是与第二个实例失败相同问题的症状。

现在进行修复 - 有两种选择:

  1. 只需使用with-redefs代替with-redefs-fn

    (with-redefs [config/environment (fn [] (:env test-case))]
      …)
    

    大部分时间这都是你想要做的,你可以认为with-redefs-fnwith-redefs背后的实现细节 - 虽然严格来说它确实有一些实用性,因为它可以重新定义动态构建的Vars集合。

  2. 使用with-redefs-fn,但将内部let表单移到匿名函数中:

    (with-redefs-fn {…}
      #(let […]
         (is …)))
    
  3. 最后,这些工作的原因和问题文本中的版本不是:

    with-redefs-fn是一个函数,因此在运行时,它的参数将在实际调用它们的运行时值之前进行计算。特别是,作为第二个参数传入的let表达式将在重新定义发生之前进行评估,因此本地调用actual将获得在重新定义之前评估(config/environment) 的结果作为其值,并且将安装该值在let的正文中创建的匿名闭包中。然而,该闭包将在重新定义的情况下被调用,因此它将在重新定义之前采用其“实际”值的概念,并将其与重新定义之后的期望值进行比较,从而产生观察到的行为。 / p>

    在闭包内部移动let,如上面的第二种方法,修复了这个不匹配问题 - let local的值是通过重新定义来计算的,一切都很好。使用with-redefs的第一种方法扩展到第二种方法。

    日志打印输出很好,因为它们只关注doseq本地,而且从不检查任何Vars。如果他们这样做,他们只会看到预重定义值。