How can I test for a function that throws an expected exception? Here is the function that throws the exception:
(defn seq-of-maps?
"Tests for a sequence of maps, and throws a custom exception if not."
[s-o-m]
(if-not (seq? s-o-m)
(throw (IllegalArgumentException. "s-o-m is not a sequence"))
(if-not (map? (first s-o-m))
(throw (IllegalArgumentException. "s-o-m is not a sequence of maps."))
true)))
I want to design a test like the following in which an exception is thrown and caught and then compared. The following does not work:
(deftest test-seq-of-maps
(let [map1 {:key1 "val1"}
empv []
s-o-m (list {:key1 "val1"}{:key2 "val2"})
excp1 (try
(seq-of-maps? map1)
(catch Exception e (.getMessage e)))]
(is (seq-of-maps? s-o-m))
(is (not (= excp1 "s-o-m is not a sequence")))))
I am getting these errors:
Testing util.test.core
FAIL in (test-seq-of-maps) (core.clj:27)
expected: (not (= excp1 "s-o-m is not a sequence"))
actual: (not (not true))
Ran 2 tests containing 6 assertions.
1 failures, 0 errors.
Obviously, I am missing something about writing tests. I am having trouble figuring that out. My project was set up with lein new, and I am running the tests with lein test.
Thanks.
The last assertion in your test is incorrect; it should be (is (= excp1 "s-o-m is not a sequence")) since map1 isn't a seq of maps.
Aside from that, it's probably clearer to use (is (thrown? ..)) or (is (thrown-with-msg? ...)) to check for thrown exceptions.
Example:
(t/is (thrown? java.lang.ClassCastException (s/valid? ::sut/int-value "x"))))
Note that you just write classname as a symbol. Use java.lang.Exception if you don't care about the exact Exception.
Related
(constantly (throw (Exception. "Don't call me"))) is how I expected to do this, based on the Clojure docs for constantly:
(constantly x)
Returns a function that takes any number of arguments and returns x.
But when I try to use constantly to create a mock function that always throws, the exception gets thrown immediately, where I am trying to define the function. Is constantly supposed to evaluate it's body right away, and cache the result? Am I running into the equivalent of C's dreaded Undefined Behaviour (in this case, "all bets are off once you depend on side effects")?
user=> (constantly (throw (Exception. "but not right now")))
Exception but not right now user/eval8734 (form-init1747541642059004341.clj:1)
user=> (repeatedly (throw (Exception. "but not right now")))
Exception but not right now user/eval8736 (form-init1747541642059004341.clj:1)
What is the idiomatic way to create to mock a callback function in a test, so that it will throw an error if called?
constantly is a function; it evaluates its argument and then returns a function that will return that evaluated result. If you want to write a function that ignores all its arguments and evaluates some expression every time it is called, you can do something like this:
(fn [& _] (throw (Exception. "Don't call me")))
Example:
((fn [& _] (throw (Exception. "Don't call me"))) :foo :bar)
;=> java.lang.Exception: Don't call me
You could also write a macro to create functions that ignore their arguments:
(defmacro ignore-args [& exprs]
`(fn ~'[& _] ~#exprs))
Example:
((ignore-args (throw (Exception. "Don't call me"))) :foo :bar)
;=> java.lang.Exception: Don't call me
I'm not entirely sure how useful such a macro would be, though, because with any sort of descriptive name (ignore-args, in this case), it would take longer to type than (fn [& _] ,,,) and doesn't really convey more semantic meaning.
If you just want a function that always throws an exception, you can do this:
(defn blowup [& args] (throw (Exception. "I just blew up")))
If you're looking for a way to make those on demand, try this instead:
(defn explosives-factory [e] (fn [& args] (throw e)))
You can see it in practice here:
user=> (defn explosives-factory [e] (fn [&args] (throw e)))
#'user/explosives-factory
user=> (def blowup (explosives-factory (Exception. "Boom!")))
#'user/blowup
user=> (blowup 123)
Exception Boom! sun.reflect.NativeConstructorAccessorImpl.newInstance0 (NativeConstructorAccessorImpl.java:-2)
I have a function param-values that throws an IllegalArgumentException when it cannot find a key in a Liberator context. I have a clojure.test unit test for this:
(testing "Non-existing key"
(is (thrown? IllegalArgumentException (param-values ctx [:baz]))))
For some reason, this test is failing, even though I can see that my function is behaving correctly in the REPL:
user> (param-values ctx [:baz])
IllegalArgumentException Missing required param baz resources/param-value (resources.clj:57)
user> (is (thrown? IllegalArgumentException (param-values ctx [:baz])))
FAIL in clojure.lang.PersistentList$EmptyList#1 (form-init2687593671136401208.clj:1)
expected: (thrown? IllegalArgumentException (param-values ctx [:baz]))
actual: nil
param-values itself is quite simple; it just maps over the specified args with param-value:
(defn param-values [ctx args & [{:keys [optional-args] :as opts}]]
(let [params (or (get-in ctx [:request :params]) {})
args (concat args optional-args)]
(map #(param-value params % opts) args)))
Of course, I have more in-depth tests for param-value, one of which is:
(testing "Arg not present"
(is (thrown-with-msg?
IllegalArgumentException #"Missing required param baz"
(param-value {} :baz))))
This test passes!
What gives? Is something about what I'm doing not jiving with the clojure.test/is macro? Do I have a typo that I'm too thick to see?
Is it because param-values returns a lazy sequence?
When using thrown-with-msg? it calls re-find on the return value of (param-value {} :baz) and thus evaluates the lazy sequence. This does not happen when just using thrown? instead.
So could you try this instead:
(is (thrown? IllegalArgumentException
(doall (param-values ctx [:baz]))))
doall will evaluate the lazy sequence.
Update based on comments:
As you are not interested in the return value of the lazy sequence, but only the side effects (throwing an exception), it's preferred to use dorun instead of doall.
Hi I have this school project that I am almost done with so I don't need help with the code, problem is I've never coded in clojure but for this assignment had to do a try and catch macro in clojure with bound forms, there are some REPL commands that are expected to give different responses for the assignment to pass,,
Anyways Im getting an error that I've been googling but nothing is specific to this problem and most explanations basically need there own explanation nothing seems to be beginner adapted so it doesnt do much for me.
(defmacro safe [bindings & code]
(if (list? bindings)
`(try
~bindings
(catch Throwable except# except#))
(if (= (count bindings) 0)
`(try ~code
(catch Throwable except# except#))
`(let ~(subvec bindings 0 2)
(try
(safe ~(subvec bindings 2) ~#code)
(catch Throwable except# except#)
(finally
(. ~(bindings 0) close))))))) ;;safe
(def divider(safe (/ 1 0)))
(def reader (safe [s (FileReader. (java.io.File. "C:/text.txt"))] (. s read)))
So the error Im getting is
=> (def v (safe [s (FileReader. (java.io.File. "C:/text.txt"))] (. s read)))
#'myProject.core/v
=> v
#<ClassCastException java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn>
So kindly anyone that knows clojure please give me some hints on what is wrong, all the hints Im getting is that there should be a paranthesis missplaced, I've checked the code over and over but cant find any misstypes etc. Thank you !
Use macroexpand and friends to help debug
(def form (quote (safe [s (FileReader. (java.io.File. "test.txt"))] (. s read))))
(pprint (macroexpand form)) ;=>
(let*
[s (FileReader. (java.io.File. "test.txt"))]
(try
(user/safe [] (. s read)) ; <--- Macro is recursive
(catch java.lang.Throwable except__1104__auto__ except__1104__auto__)
(finally (. s user/close))))
Macro is recursive, so this is not the full expansion
(pprint (clojure.walk/macroexpand-all form)) ;=>
(let*
[s (new FileReader (new java.io.File "test.txt"))]
(try
(try
((. s read)) ; <-- Too many parenthesis!
(catch ...
The read call returns an integer, which is in turn being called as a function in the recursive macro expansion.
(FileReader. (java.io.File. "/tmp/text.txt"))
is giving you the value of the first character on the file
cat /tmp/text.txt => abcd
(let [s (FileReader. (java.io.File. "/tmp/text.txt"))] (. s read)) => 97
same as
(int \a)
and your macro expect a function. try:
(safe [s (FileReader. (java.io.File. "/tmp/text.txt"))] #(+ 6)) or (safe [s (FileReader. (java.io.File. "/tmp/text.txt"))] (fn [] (. s read)
Solved!
Missing unquote slicing in the third try block, causing exception
java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn
this was caused due to extra paranthesis when reading s recursivly,
macroexpand ex.
(pprint (macroexpand-all form))
(let*[s
(new FileReader
(new File "test.txt"))]
(try
(try
((.s read)) ;<= here
Had to change the third try/catch from
(try
(safe ~(subvec bindings 2) ~#code)
to:
(try
(safe ~#(subvec bindings 2) ~#code)
To my understanding the problem was that I was returned a list with a paranthesis like (1(2 3)) causing exception when read, unquoting makes it look (1 2 3) and can be read or (in this case) casted from java to clojure.
reservations for misspellz or calling shit the wrong name! :)
Many thanks to A.Webb and patz.
I don't know how to implement this piece of Python code in Clojure
for i in range(3):
try:
......
except e:
if i == 2:
raise e
else:
continue
else:
break
I wonder why something so simple in Python is so hard in Clojure. I think the difficulty is because Clojure is a functional programming language and thus is not suitable for such an imperative task. This is my attempt:
(first
(remove #(instance? Exception %)
(for [i (range 3)]
(try (......)
(catch Exception e
(if (== i 2)
(throw e)
e)))))))
It is very ugly, and worse, it doesn't work as expected. The for loop is actually evaluated fully instead of lazily (I realized this when I put a println inside).
If anyone has a better idea to implement that, please enlighten me.
Similar to Marcyk's answer, but no macro trickery:
(defn retry
[retries f & args]
(let [res (try {:value (apply f args)}
(catch Exception e
(if (zero? retries)
(throw e)
{:exception e})))]
(if (:exception res)
(recur (dec retries) f args)
(:value res))))
Slightly complicated because you can't recur inside a catch clause. Note that this takes a function:
(retry 3 (fn []
(println "foo")
(if (zero? (rand-int 2))
(throw (Exception. "foo"))
2)))
=>
foo ;; one or two or three of these
foo
2
Here's one approach:
(defmacro retry
"Evaluates expr up to cnt + 1 times, retrying if an exception
is thrown. If an exception is thrown on the final attempt, it
is allowed to bubble up."
[cnt expr]
(letfn [(go [cnt]
(if (zero? cnt)
expr
`(try ~expr
(catch Exception e#
(retry ~(dec cnt) ~expr)))))]
(go cnt)))
Example from the REPL:
user> (retry 2 (do (println :foo) (throw (RuntimeException. "foo"))))
:foo
:foo
:foo
; Evaluation aborted.
(Passing 2 to retry asks expr to be retried twice it if fails the first time round, for a total of three attempts. Three :foos are printed, because the println occurs before the throw in the do form passed to retry. The final ; Evaluation aborted. means an exception was thrown.)
Also, about the for loop from your snippet:
If you try looping over a longer range (replace (range 3) with (range 10), say), the output will end after i reaches 3. Also, if you put in a println before the form which throws the exception, it will of course print out whatever you pass to it; if the println occurs after the exception-throwing form, there will be no printout. In any case, at most three calls to println will be executed (assuming an exception is thrown on every iteration).
(cond (every? nil? (for [x (range (inc retry)) :while (not #tmp-doc)]
...do sth) )
;all failed
:else
;at least one success
You can do like this:
(defn retry
"Tries at most n times, return first try satisfying pred or nil"
[times pred? lazy-seq]
(let [successful-trial (drop-while (complement pred?) (take times lazy-seq))]
(if (empty? successful-trial)
nil
(first successful-trial))))
Then you could use the function as such:
(when-not (retry 3 pos? (repeatedly #(rand-nth [-1 -2 -3 2 1]))
(throw (Exception. "my exception message"))
This would try at most three times to take a positive number at random from the vector and if it doesn't succeed, throws an exception.
Retry with sleep and another implementation based on this question's answers:
(defn retry [retries sleep-ms func url options]
(let [{:keys [status headers body error] :as resp} #(func url options)]
(if error
(do
(log/error (str "Retry " retries " returned error: " e))
(Thread/sleep sleep-ms)
(if (= retries 1)
resp
(retry (dec retries) sleep-ms func url options)))
resp)))
What is the proper way to do the following in clojure?
(ns todo.test.models.task
(:use [clojure.test]))
(deftest main-test
(is (thrown? Exception (throw Exception "stuff")))
(is (not (thrown? Exception (+ 2 3))))
)
First testcase runs fine but the whole snippet returns "Unable to resolve symbol: thrown?"
is is a macro that looks for the symbol thrown? in its body and build tests.
thrown? is not actually a function you can call. The default behaviour of is fails the test if an exception is thrown that was not beeing looked for, so you can just remove the (not (thrown? from the above example and get the result you are looking for.
thrown? is a special assertion that must show up after is, so you can't nest it in other expressions, so in the context of the is macro, the second assertion will not understand the symbol thrown?.
You could just say:
(deftest main-test
(is (thrown? Exception (throw (Exception. "stuff"))))
(is (= 5 (+ 2 3))))
If an exception is thrown in (+ 2 3), clojure.test will report 1 :error and 0 :fail and dump the stack trace.
Also note that your (throw Exception "stuff") is incorrect - you need to construct the Exception correctly inside the throw.
Use doseq if you want to do it for many statements:
(testing "bla"
(doseq [x [1 2 3 4]]
(my-dangerous-func! x)))
I know this is an old question but..
In addition to the above answers, if you really want a not-thrown? assertion, you can extend the is macro by adding your own e.g.
(defmethod assert-expr 'not-thrown? [msg form]
;; (is (not-thrown? c expr))
;; Asserts that evaluating expr does not throws an exception of class c.
;; Returns the exception thrown.
(let [klass (second form)
body (nthnext form 2)]
`(try ~#body
(do-report {:type :pass, :message ~msg,
:expected '~form, :actual nil})
(catch ~klass e#
(do-report {:type :fail, :message ~msg,
:expected '~form, :actual e#})
e#))))
This should then work as your original expectations
((deftest main-test
(is (thrown? Exception (throw (Exception. "stuff"))))
(is (not-thrown? Exception (+ 2 3)))))
However, please note that clojure.test will always report an error if an exception occurs in your function but if you have a special use-case for this, there you go.