First of all, sor开发者_StackOverflow社区ry if I am screwing up some terminology; I'm pretty new to Clojure. I am trying to write a very simple test using Lazytest that depends on a var binding. I can not seem to rebind a var in the test file and have the code under test use that binding.
Here is the code I am trying to test:
(ns liar-liar.core
(:gen-class))
(def *input-file-name*)
(defn parse-input
"Just print return a var for now..."
[]
*input-file-name*)
(defn -main [& args]
(binding [*input-file-name* (first args)]
(println (parse-input))))
And here is the test:
(ns liar-liar.test.core
(:use lazytest.describe)
(:use liar-liar.core))
(binding [*input-file-name* "my-input-file"]
(describe parse-input "Just returns a var"
(it "returns a var"
(= "my-input-file" (parse-input)))))
When I try to run this test, I get this error:
java.lang.IllegalStateException: Var liar-liar.core/*input-file-name* is unbound.
Interestingly enough, if I move the binding form:
(ns liar-liar.test.core
(:use lazytest.describe)
(:use liar-liar.core))
(describe parse-input "Just returns a var"
(it "returns a var"
(binding [*input-file-name* "my-input-file"]
(= "FAIL" (parse-input)))))
The test works as it should, but the reporting isn't ideal, as it doesn't print the value of the (parse-input) expression (the test passes if I replace "FAIL" with "my-input-file" though):
FAILURE: Namespaces liar-liar.test.core #'liar-liar.core/parse-input Just returns a var returns a var
at liar_liar/test/core.clj line 7
Expression: (binding [*input-file-name* my-input-file] (= FAIL (parse-input)))
Result: false
Local bindings:
{}
Is there some other way I should be going about doing this kind of testing?
Thanks! Dan
I think your expectation of how this should work is reasonable, but I have a feeling the describe
and it
macros are evaluating *input-file-name*
before your binding form has a chance to bind it. I've found in my brief Lazytest explorations that I'm better off sticking with the forms provided by the framework than trying to wrap either of those two macros with let
or binding
forms.
These kinds of problems seem to be fairly frequent (for me, anyway) when using dynamic binding to "push" arguments to a function. It's much more reliable and understandable to actually pass that argument in, where possible.
As described by Stuart Sierra on the Clojure google group (block quote's not working here):
Both describe
and it
create functions. That is, they expand out
to (fn [] ...)
. Wrapping binding
around the creation of a fn has
no effect.
For finer control over where the fn gets created and how failures get
reported, you can use do-it
and expect
.
(describe ... (do-it ... (binding ... (expect ...)))
This will produce the results you're looking for.
http://groups.google.com/group/clojure/browse_thread/thread/d181e4731bdf9beb
Indeed, they did produce the results I was looking for :)
精彩评论