2016-05-03 22 views
1

有一些基本的東西我沒有在這裏。我期待下面的測試通過。但第二個測試用例「分段」/「分段」失敗。它好像與-reffs-fn一樣未能通過測試用例實例。但伐木業說一切都很好。這很混亂。with -refs-fn無法從do-seq獲取綁定?

(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無法根據當前測試用例重新定義config/environment函數?

回答

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 …))) 
    

最後,這些工作和問題文本版本不原因:

with-redefs-fn是一個函數,因此在運行時,它的參數將在其傳入的運行時值實際調用之前進行評估。特別是,您傳入的let表達式作爲第二個參數將在重新定義之前進行評估,因此稱爲actual的本地將獲得評估(config/environment)之前重定義作爲其值的結果,並且該值將安裝在let的身體中創建的匿名關閉中。然而,這種封閉將隨着重新定義而被調用,因此它將在重新定義之前將其「實際」價值的概念與重新定義之後的期望相比較,從而導致觀察到的行爲。

將閉合內部的let移動到上面的第二種方法中,修復了這個不匹配問題 - 局部值的計算與重新定義一致,一切正常。使用with-redefs的第一種方法擴展到第二種方法。

日誌打印輸出很好,因爲他們只關注doseq本地並且從不檢查任何Vars。如果他們這樣做了,他們只會看到重新定義的價值。

+0

我現在正在努力理解with-redefs-fn的效用。 with-redefs像冠軍一樣工作。 –

+0

'with-redefs-fn'是一個實現細節 - 它存在並且是公有的,所以'with-redefs'可以在其擴展中使用它。用戶代碼通常不應該直接調用它。也許我應該在答案中提到這一點! –

+0

其實我回來了。大多數情況下'with-redefs'更方便,但'with-redefs-fn'允許重新創建一個動態創建的Vars集合,所以它在某些場景中可能很有用。 –