我有一个小单元测试宏
(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”之后的值打印错误。
答案 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 reader和this SO answer explaining the ins and outs of symbols in clojure。
答案 1 :(得分:0)
当你有'Is'宏打印时,你有一个横切关注点。让'Is'宏返回一个包含这样的内容的列表(:传递形式实际答案期望答案)或(:失败形式实际答案期望答案)。您可能有一个DefTest宏来聚合您的断言。那是你应该给你答案的地方。