繁体   English   中英

在clojure.test中将箭头私有defns线程化

[英]Threading arrow private defns in clojure.test

在新的lein new app arrow-mve的MVE(最小可行示例)命名空间中考虑以下功能。 功能extract-one公共的,功能extract-two是私有的。 我包括main-函数只是为了完整性,以及它可能引起我的问​​题的可能性:

(ns arrow-mve.core
  (:gen-class))

(defn extract-one [m]
  (-> m :a))

(defn- extract-two [m]
  (-> m :a))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

在我的并行测试名称空间中,我可以如下测试这些功能。 我可以通过直接调用或使用箭头线程宏->测试公共函数extract-one 还要注意,在直接调用中,使用私有函数extract-two完整的Var来引用我没有问题。 这些测试通过:

(ns arrow-mve.core-test
  (:require [clojure.test :refer :all]
            [arrow-mve.core :refer :all]))

(deftest test-one-a
  (is (= 1 (extract-one {:a 1, :b 2}))))

(deftest test-one-b
  (is (= 1 (-> {:a 1, :b 2}
               extract-one))))

(deftest test-two-a
  (is (= 1 (#'arrow-mve.core/extract-two
            {:a 1, :b 2}))))

但是,当我尝试使用箭头宏调用私有函数extract-two时,出现编译错误:

(deftest test-two-b
  (is (= 1 (-> {:a 1, :b 2}
               #'arrow-mve.core/extract-two))))

$ lein test
 Exception in thread "main" java.lang.RuntimeException: Unable to resolve var: arrow.mve.core/extract-two in this context, compiling: (arrow_mve/core_test.clj:10:12) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6875) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) 

当我使测试更加复杂时,事情变得更加奇怪。

(deftest test-two-b
  (is (= {:x 3.14, :y 2.72}
         (-> {:a {:x 3.14, :y 2.72}, :b 2}
             #'arrow-mve.core/extract-two))))

$ lein test
 Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Symbol, compiling:(arrow_mve/core_test.clj:18:10) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6875) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) 

再次,测试以直接致电形式通过:

(deftest test-two-b
  (is (= {:x 3.14, :y 2.72}
         (#'arrow-mve.core/extract-two
          {:a {:x 3.14, :y 2.72}, :b 2}))))

我怀疑问题是通过deftest进行的宏链接的deftest ,它is Var的阅读器宏#'和arrow宏,并想知道这是设计deftest还是潜在的错误。 当然,在我的实际应用程序(不是此MVE)中,我有很长且很深的调用链,这使使用箭头宏变得非常可取。

这是答案(不同的ns):

主要名称空间:

(ns clj.core
  (:require [tupelo.core :as t] ))
(t/refer-tupelo)

(defn extract-one [m]
  (-> m :a))

(defn- extract-two [m]
  (-> m :a))

测试名称空间:

(ns tst.clj.core
  (:use clj.core
        clojure.test )
  (:require [tupelo.core :as t]))
(t/refer-tupelo)

(deftest test-one-a
  (is (= 1 (extract-one {:a 1, :b 2}))))

(deftest test-one-b
  (is (= 1 (-> {:a 1, :b 2}
               extract-one))))

(deftest test-two-a1
  (is (= 1 (#'clj.core/extract-two {:a 1, :b 2}))))

;(deftest test-two-b
;  (is (= 1 (-> {:a 1, :b 2}
;               clj.core/extract-two))))  ; fails: not public

;(deftest test-two-b1
;  (is (= 1 (-> {:a 1, :b 2}
;               #'clj.core/extract-two))))
;     fails: can't cast PersistentArrayMap to Symbol

(deftest test-two-b
  (is (= 1 (-> {:a 1, :b 2} 
               (#'clj.core/extract-two)))))  ; works

答案是var引用必须在括号内。 线程宏都具有形式(伪代码)的测试:

(if (not (list? form))
  '(form)
  form)

像这样的形式

(-> 1
    inc)

变成

(-> 1
    (inc))

在其余线程发生之前。 由于var不是符号,因此if测试似乎对您失败。 将var包含在列表中作为函数调用可解决此问题。

我更喜欢始终将函数调用以线程形式括在括号中,并且即使通常是允许的,也不使用任何“裸”函数:

(-> 1
    (inc)    ; could have typed "inc" w/o parens
    (* 2))   ; must use parens since more than 1 arg
;=> 4

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM