我怎样才能得到Clojure:pre&:post来报告他们失败的价值?

Ste*_*gle 26 clojure clojurescript

(defn string-to-string [s1] 
  {:pre  [(string? s1)]
   :post [(string? %)]}
  s1)
Run Code Online (Sandbox Code Playgroud)

我喜欢:pre和:post条件,它们允许我弄清楚我何时更快地将"方形钉子放在圆孔中".也许这是错误的,但我喜欢将它们用作一种可怜的勒芒式检查器.这不是哲学,这是一个简单的问题.

在上面的代码中我似乎很容易确定这s1是:pre条件中的函数参数.类似地,%在:post条件总是函数返回值.

我想是打印的值s1或者%当任的这些相应的条件Asse田内失效.所以我得到了类似的东西

(string-to-string 23)

AssertionError Assert failed: (string? s1) 
(pr-str s1) => 23 
Run Code Online (Sandbox Code Playgroud)

AssertionError包含每个变量的单行,该变量被识别为来自函数参数列表并且在失败测试中被引用.当函数的返回值未通过:post条件时,我也想要类似的东西.

这将使得在尝试从AssertionError进行诊断时快速发现我滥用函数的方式变得微不足道.它至少会让我知道值是否nil是实际值(这是我犯的最常见的错误).

我有一些想法,这可能与宏来完成,但我想知道如果有办法基本上只是重新定义了任何安全和全球性的方式(defn和(fn朋友们这样做是:pre和:post也将打印导致测试值(S)失败.

opt*_*evo 27

您可以使用is宏来包装谓词clojure.test

(defn string-to-string [s1] 
  {:pre  [(is (string? s1))]
   :post [(is (string? %))]}
 s1)
Run Code Online (Sandbox Code Playgroud)

然后你得到:

(string-to-string 10)
;FAIL in clojure.lang.PersistentList$EmptyList@1 (scratch.clj:5)
;expected: (string? s1)
;actual: (not (string? 10))
Run Code Online (Sandbox Code Playgroud)

  • 很好,我喜欢.这是一个合理的妥协,让我90%.尽管如此,我认为如果在Clojure 1.7+中,它们会自动打印出所有即时变量的值(认识到refs,懒惰序列,以及probalby其他我没想到的东西可能会导致问题). (3认同)
  • 因为在编码和输出中看起来有点笨拙,我认为这可以通过clojure的核心本身变得更简单.也许[clojure.spec](https://clojure.org/about/spec)有一些比`:pre`更整洁的东西. (2认同)

Dav*_*ood 12

@octopusgrabbus通过提议暗示了这一点(try ... (catch ...)),并且你提到那可能太嘈杂,并且仍然包含在断言中.一个更简单,噪声更小的变体就是一个简单的(or (condition-here) (throw-exception-with-custom-message))语法,如下所示:

(defn string-to-string [s1] 
  {:pre  [(or (string? s1)
              (throw (Exception. (format "Pre-condition failed; %s is not a string." s1))))]
   :post [(or (string? %)
              (throw (Exception. (format "Post-condition failed; %s is not a string." %))))]}
  s1)
Run Code Online (Sandbox Code Playgroud)

这实际上允许您使用自定义错误消息的前置条件和后置条件 - 前置条件和后置条件仍然像通常那样进行检查,但是在AssertionError发生之前会对您的自定义异常进行求值(并因此抛出).