Example adapted from the standard documentation for with-test:
(ns my-test
(:require [clojure.test :refer :all]))
(with-test
(defn my-function [x y]
;; (assert false)
(+ x y))
(is (= 4 (my-function 2 2)))
(is (= 7 (my-function 3 4))))
(test #'my-function)
The 'with-test' block and the 'test' blocks are evaluated correctly (using C-x C-e in emacs/cider).
But then if I uncomment the 'assert' line they still are!
Directly evaluating (my-function 2 2) fails.
Related
I want to check if the right instance is used.
But while the repl gives me true, the actual test returns nil.
Idk why
(ns my-app.queue)
(def queue (atom clojure.lang.PersistentQueue/EMPTY))
(ns my-app.queue-test
(:require [my-app.queue :as sut]
[clojure.test :refer :all]))
(deftest queue-type-test
(is (instance? clojure.lang.PersistentQueue #sut/queue)))
;repl output
;(instance? clojure.lang.PersistentQueue #sut/queue) ;=> true
The command lein test gives me:
FAIL in (queue-type-test) (queue_test.clj:6)
expected: (instance? clojure.lang.PersistentQueue (clojure.core/deref sut/queue))
actual: nil
I know the test itself is not really useful, but I can't figure out why this behaves like this.
tl;dr: both is and # are macros. Most obvious fix would be something like:
(deftest queue-type-test
(let [queue #sut/queue]
(is (instance? clojure.lang.PersistentQueue queue)))
clojure.test docs don't make it immediately obvious, but is is a pretty tricky macro that looks inside its body. Here's a snippet from the docstring:
user> (is (= 5 (+ 2 2)))
FAIL in (:1)
expected: (= 5 (+ 2 2))
actual: (not (= 5 4))
false
Notice actual: (not (= 5 4)). It's clear that it did not evaluate = so that it can show us the result of (+ 2 2). Here are all the special cases for assert-expr multimethod.
If I try to check a macro spec with clojure.spec.test.alpha, no tests are run, but if I define the same macro as a function with the same spec, a sequence of tests are run against the function. I can always generate parameters to unit test the macro, but is there a way to get that for free with spec? Here is an example:
(ns private.tmp.spec-test
(:require [clojure.spec.alpha :as spec]
[clojure.spec.test.alpha :as stest]))
;;; Macro
(defmacro twice' [x]
`(* 2.0 ~x))
(spec/fdef twice'
:args (spec/cat :x double?)
:ret double?
:fn (fn [{{:keys [x]} :args, x2 :ret}]
(or (and
(Double/isNaN x)
(Double/isNaN x2))
(= x2 (+ x x)))))
(println (stest/summarize-results (stest/check `twice'))) ;; {:total 0}
;;; Function
(defn twice [x]
(* 2.0 x))
(spec/fdef twice
:args (spec/cat :x double?)
:ret double?
:fn (fn [{{:keys [x]} :args, x2 :ret}]
(or (and
(Double/isNaN x)
(Double/isNaN x2))
(= x2 (+ x x)))))
(println (stest/summarize-results (stest/check `twice))) ;; {:total 1, :check-passed 1}
I asked this question on the Clojure, Google Group and the consensus is that checking macros is not supported. The preferred method of testing is by generating params for unit tests by test.check.
https://groups.google.com/forum/#!topic/clojure/RxnwKcha0cE
If any step in my test setup fails, I want to report this as a failure, and cease any subsequent tests in the current deftest block (or current namespace). One way to do this now:
(if some-condition-is-ok
(do
... do tests)
(is (= 1 0) "Failure, condition not met")
The above:
Reports failure if some-condition-is-ok is not met
Does not run any tests, since the setup condition was not met
Except that it does not flow well, and does not work well for multiple conditions. I'd like something like:
(let [;; setup here...]
(assert-or-stop-tests some-condition-is-ok)
... continue with tests here
Any ideas on a clean way to do this?
You could use Mark Engelberg's better-cond for this:
(require '[better-cond.core :as b]
'[clojure.test :refer [is]])
(def some-condition-is-ok true)
(def some-other-condition-is-ok false)
(deftest a-test
(b/cond
:let [#_"setup here..."]
:when (is some-condition-is-ok)
:let [_ (is (= 0 1))]
:when (is some-other-condition-is-ok)
:let [_ (is (= 1 2))]))
Or if you want to avoid the :let [_ ,,,], you could define your own macro:
(defmacro ceasing [& exprs]
(when-let [[left & [right & less :as more]] (seq exprs)]
(if (= :assert left)
`(when (is ~right)
(ceasing ~#less))
`(do
~left
(ceasing ~#more)))))
(deftest b-test
(let [#_"setup here..."]
(ceasing
:assert some-condition-is-ok
(is (= 0 1))
:assert some-other-condition-is-ok
(is (= 1 2)))))
Where in the clojurescript library can I access a function to compile snippets of clojure into js?
I need this to run in the clojure (not clojurescript) repl:
(->js '(fn [x y] (+ x y)))
=> "function(x,y){return x+y}"
Snippet compilation from Clojure REPL
(require '[cljs.analyzer.api :refer [analyze empty-env]])
(require '[cljs.compiler.api :refer [emit]])
(let [ast (analyze (empty-env) '(defn plus [a b] (+ a b)))]
(emit ast))
;; result
"cljs.user.plus = (function cljs$user$plus(a,b){\nreturn (a + b);\n});\n"
Snippet compilation from ClojureScript REPL:
(require '[cljs.js :refer [empty-state compile-str]])
(compile-str (empty-state) "(defn add [x y] (+ x y))" #(println (:value %)))
;; Output (manually formatted for easier reading)
cljs.user.add = (function cljs$user$add(x,y){
return (x + y);
});
compile-str takes a callback as the last argument. It will be called with a map either with a key :value containing result JS as a string or :error with the compilation error.
In both cases org.clojure/tools.reader is needed on your classpath.
there is a lightweight alternative: https://github.com/kriyative/clojurejs which creates the right output asked by the question.
Examples can be seen here: https://github.com/kriyative/clojurejs/wiki/Examples
Found some odd behavior in midje, not sure if it's midje related, or due to my misunderstanding of some clojure constructs, but it's puzzling:
Inside a facts statement, a for loop is not getting called:
(ns t1
(:require [midje.sweet :refer :all ] )
)
(facts
(println "ok") ; -- this prints fine
(for [val '(1 2 3)] (println val)) ; this does not
(fact "junk"
(> (.length "aaaaha") 3) => true ))
Thought maybe it had something to do with the for being overwritten in the ns but calling clojure.core/for behaves similarly.
clojure.core/for "...yields a lazy sequence..."
You need to realize the sequence to see its side effects.
(doall (for [val '(1 2 3)] (println val)))
I'd suggest using something more appropriate like clojure.core/doseq:
(doseq [val '(1 2 3)] (println val))