帮助在Clojure中设计一个小的单元测试宏

时间:2009-08-08 14:24:05

标签: functional-programming lisp clojure

我有一个小单元测试宏

  (defmacro is [expr value]
        `(if (= ~expr ~value)
             'yes
             (println "Expected " ~value "In" ~expr "But Evaluated to" ~expr)))

如何正确编写错误消息? 现在它给出了

Clojure 1.0.0-
1:1 user=> (is (+ 2 2) 4)
user/yes
1:2 user=> (is (+ 2 2) 5)
Expected  5 In 4 But Evaluated to 4

我想评估表达式,如果评估的值与其他预期匹配,则说“是” 使用未评估的表达式而不是“In”之后的值打印错误。

2 个答案:

答案 0 :(得分:11)

原始答案

我认为这就是你要找的东西:

(defmacro is [expr value]
    `(if (= ~expr ~value)
         true
         (println "Expected " ~value "In" (str (quote ~expr)) 
                  "But Evaluated to" ~expr)))

(quote ~expr)做的是将expr表示的s表达式带入“模板”,但阻止对其进行评估,然后将str应用于未评估的s表达式它成为一个字符串,用于与错误消息的其他字符串连接。所以,:

user=> (is (+ 2 2) 5)
Expected  5 In (+ 2 2) But Evaluated to 4

产生所需的行为。

您可以简单地使用'yes作为测试成功的报告,而不是使用true来报告成功,而是:

user=> (is (+ 2 2) 4)
true

并避免将'yes作为合格符号返回的问题。如果由于某种原因需要符号,那么您可以创建一个关键字:

(defmacro is [expr value]
    `(if (= ~expr ~value)
         :yes
         (println "Expected " ~value "In" (str (quote ~expr)) 
                  "But Evaluated to" ~expr)))


user=> (is (+ 2 2) 4)
:yes



回答问题中提出的问题

你在评论中提问:

  

对不起,我的问题应该更清楚了。在这种情况下,符号和关键字之间有什么区别?

考虑您的原始定义(通过更正使错误以您想要的方式返回):

(defmacro is [expr value]
`(if (= ~expr ~value)
     'yes
     (println "Expected " ~value "In" (str (quote ~expr)) 
              "But Evaluated to" ~expr)))

我想你希望'yes认为可以用来在其他环境中对'yes进行测试(人们经常在介绍性的lisp文本中看到这些类型的测试)。但是在您的宏定义中使用了'yes,它在测试通过时返回一个限定符号:

user=> (is (+ 2 2) 4)
user/yes

现在,这不是你想要的。想象一下,你这么说:

user=> (= 'yes (is (+ 2 2) 4))
false

要获得true答案,您必须这样说(使用语法引用):

user=> (= `yes (is (+ 2 2) 4))
true

如果您定义了宏以返回:yes,那么您将获得可检查的返回,而无需语法引用您用于执行检查的对象:

user=> (= :yes (is (+ 2 2) 4))
true

但这一切都是多余的,因为您真的对(+ 2 2)是否返回4感兴趣,即您的断言是true还是false而不是'yes } equals``yes or'yes ; you can just have it return true`并避免这个检查步骤(在现实世界中)。

在任何情况下,要了解符合条件的符号,您需要阅读docs on the clojure readerthis SO answer explaining the ins and outs of symbols in clojure

答案 1 :(得分:0)

当你有'Is'宏打印时,你有一个横切关注点。让'Is'宏返回一个包含这样的内容的列表(:传递形式实际答案期望答案)或(:失败形式实际答案期望答案)。您可能有一个DefTest宏来聚合您的断言。那是你应该给你答案的地方。