How to print test names in Leiningen? - unit-testing

I would like to print each of my leiningen test methods as they are running. I have a lein tests file that is relatively simple:
(defn myfixture [b]
(do
(println "start")
(b)
(println "end")
)
)
(deftest test1 [] .....
I want to see "test1" print out at the repl when I run the tests. Is there a simple way to print the method name (either by calling a method of b in myfixture, or, in the invocation of "lein test")?

You can get the name of a function like this:
(defn function-name [f]
(:name (meta f)))
(defn my-func []
(println "Hello, world!"))
(let [f my-func]
(function-name f))
;=> my-func
I don't know if the facility that you are looking for exists in the regular clojure.test but midje has some pretty extensive fixture facilities, this link is maybe worth checking out.

Related

Clojure's load-string works in the repl but not in `lein run`

When I start a repl with lein repl I can run the function greet and it works as expected.
(ns var-test.core
(:gen-class))
(declare ^:dynamic x)
(defn greet []
(binding [x "Hello World."]
(println (load-string "x"))))
(defn -main [& args]
(greet))
But if run the code via lein run it fails with
java.lang.RuntimeException: Unable to resolve symbol: x in this context.
What am I missing?
Is the var x dropped during compilation, despite being declared, since it is never used outside of the string?
Edit:
Solution
#amalloy's comment helped me understand I need to bind *ns* in order load the string within the expected namespace, instead of a new, empty namespace.
This works as expected:
(ns var-test.core
(:gen-class))
(declare ^:dynamic x)
(defn greet []
(binding [x "Hello World."
*ns* (find-ns 'var-test.core)]
(println (load-string "x"))))
(defn -main [& args]
(greet))
Wow, I've never seen that function before!
According to the docs, load-string is meant to read & load forms one-at-a-time from an input string. Observe this code, made from my favorite template project:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require [tupelo.string :as str]))
(dotest
(def y "wilma")
(throws? (eval (quote y)))
(throws? (load-string "y"))
So it appears that load-string starts with a new, empty environment, then reads and evaluates forms one at a time in that new env. Since your x is not in that new environment, it can't be found and you get an error.
Try it another way:
(load-string
(str/quotes->double
"(def ^:dynamic x)
(binding [x 'fred']
(println :bb (load-string 'x'))) " ))
;=> :bb fred
In this case, we give all the code as text to load-string. It reads and eval's first the def, then the binding & nested load-string forms. Everything works as expected since the working environment contains the Var for x.
Some more code illustrates this:
(spy :cc
(load-string
"(def x 5)
x "))
with result
:cc => 5
So the eval produces the var x with value 5, then the reference to x causes the value 5 to be produced.
To my surprise, the partial load-string works in a fresh REPL:
demo.core=> (def x "fred")
#'demo.core/x
demo.core=> (load-string "x")
"fred"
So load-string must be coded to use any pre-existing
REPL environment as the base environment. When using lein run, there is no REPL environment available, so load-string starts with an empty environment.

Why does the macroexpand does not print the results of defmacro?

I am a newbie to Clojure and currently trying to invoke a simple macro using defmacro and macroexpand.
(ns tutorial.core
(:gen-class)) ; namespace
(defn -main [& args]
(defmacro Simple [] (println "Hello"))
(macroexpand '(Simple))
)
Is there something I have missed? it seems the program runs without any problems but the results are not coming out as expected.
I expect the results to print out as Hello, but no outputs result from this script.
Preface:
Please see this past question for an overview of the best way to write a macro (IMHO).
Answer:
You shouldn't define the macro in the main function. Try this:
(ns demo.core)
(defmacro happy
[]
`(println "I'm happy!")) ; *** notice the backtick! ***
(defn -main [& args]
(println :expanded (macroexpand '(happy)))
(happy)
)
start up a repl:
~/expr/demo > lein repl
demo.core=> (macroexpand '(happy))
;=> (clojure.core/println "I'm happy!")
and we see that it works. Try running from the command line:
~/expr/demo > lein run
:expanded (happy) ; <= ***** OOOPS! *****
I'm happy!
Try changing the single-quote into a syntax-quote (aka backtick), then run:
(defn -main [& args]
(println :expanded (macroexpand `(happy)))
(happy))
~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
The explanation is that the syntax-quote will fully-qualify the Var happy => demo.core/happy (you can see the same effect on the println Var inside of the happy macro itself because of that syntax-quote). This allows the macroexpand to work properly. Compare with a single-quote:
(defn -main [& args]
(println :expanded (macroexpand '(demo.core/happy)))
(happy))
~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
The cause of this behavior is that, in the REPL, we see from the prompt that we are in the demo.core namespace, so happy is resolved as demo.core/happy. When we use lein run, however, observe:
(defn -main [& args]
(println *ns*)
(println (ns-name *ns*)))
with result:
~/expr/demo > lein run
*ns* => #object[clojure.lang.Namespace 0xb625b00 "user"]
(ns-name *ns*) => user
and we see that the *ns* is set to the user namespace and happy cannot be resolved to the Var demo.core/happy unless we fully qualify it either manually or using syntax-quote in the code.
You can find a list of documentation here. Be sure especially to study the Clojure CheatSheet.
For macros, the book Mastering Clojure Macros is also good.
Your macro function doesn't return code, but does the printing immediately. This is very bad style as it has unforeseen consequences.
If you were to use this is a function:
(defn hello [] (Simple))
It prints "Hello" when the function is created. The code being inserted in the function is the result fo println which is nil, thus you have created this:
(defn hello [] nil)
Then if you call hello 3 times none of the calls will no any printing since your macro doesn't produce anything else than nil. If you change your macro to return structure:
;; The quote that makes all the difference
(defmacro Simple [] '(println "Hello"))
Then if will not print anything during the createion of hello, but the expansion would be (println "Hello") and the same fucntion hello would become:
(defn hello [] (println "Hello"))

Clojure-tagged literals::Raise an error-No dispatch macro for it

tmp2/src/data_readers.clj
{ct/G tmp2.core/foo}
tmp2/src/tmp2/core.clj
(ns tmp2.core)
(defn foo
[x]
(println x "Hello, World!"))
(defn -main
[& args]
(println "Hello, World!")
(foo 123)
(#ct/G "abc"))
When "lein run" in the project directory, it show the result "abc Hello, World!", but raise an error.
Caused by: java.lang.RuntimeException: No dispatch macro for: c
at clojure.lang.Util.runtimeException(Util.java:221)
at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:851)
at clojure.lang.LispReader.read(LispReader.java:285)
at clojure.lang.LispReader.readDelimitedList(LispReader.java:1398)
at clojure.lang.LispReader$ListReader.invoke(LispReader.java:1243)
at clojure.lang.LispReader.read(LispReader.java:285)
at clojure.lang.LispReader.readDelimitedList(LispReader.java:1398)
at clojure.lang.LispReader$ListReader.invoke(LispReader.java:1243)
at clojure.lang.LispReader.read(LispReader.java:285)
at clojure.lang.LispReader.read(LispReader.java:216)
at clojure.lang.Compiler.load(Compiler.java:7630)
Where should I change the code? Any help would be appreciated
in fact, there are two problems here:
1) your foo function returns nil, and it appears that the reader function can't return literal nil. So you have to actually return something from foo:
(defn foo [x]
(println x "Hello, World!")
:something)
or, in case you really need nil in generated code, you can do this:
(defn foo [x]
(println x "Hello, World!")
'(quote nil))
2) the second problem is that you actually try to call the result of your tag application here:
(#ct/G "abc")
the syntax #tag value is evaluated at read-time with (tag-fn value), and then the result is literally put into the source code. when you use the extra pair of parens, that is what happens in your case:
((foo "abc")) and, as the foo function return foo-return-value, it is then left to be (foo-return-value) , and this, in turn, leads to an error.
so,
(defn foo [x]
(println x "Hello, World!")
:nothing)
(defn -main
[& args]
(println "Hello, World!")
(foo 123)
#ct/G "abc")
should probably work
OK, got it working.
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn foo
[x]
(println :foo-reader x)
x)
(dotest
(println :test-foo-plain)
(foo 123)
(println :test-foo-reader)
(println #ct/G "abc")
(println :test-leave))
Note the location and contents of the Data Readers file. It must be at the ROOT of the classpath. In this case that is src/clj:
~/expr/demo > cat src/clj/data_readers.clj
{ct/G tst.demo.core/foo}
and test results:
> lein test
:foo-reader abc ; <====== NOTICE!
-------------------------------
Clojure 1.10.1 Java 14
-------------------------------
:test-foo-plain
:foo-reader 123
:test-foo-reader
abc
:test-leave
Notice that the foo reader for the tagged literal was invoked when the source code file was read, before it was compiled or the test was executed.
Regarding the root of the classpath
This is controlled for Lein projects by these entries in projects.clj:
:source-paths ["src/clj"]
:java-source-paths ["src/java"]
:test-paths ["test/clj"]
If you don't have the clj and java bits (some projects also segment cljc and cljs files into separate directory trees as well), you will need to modify either project.clj or the file location.

How to output successful tests from `lein test`?

Using clojure.test, when running lein test, the default settings only print out the number of assertions, like "Ran 12 tests containing 19 assertions," the details for failed tests, and the namespaces tested. I would like an output of the successful tests as well, so I can see what tests were actually run. Frameworks like Mocha in JS have this behavior by default.
For instance, if the following test passed:
(deftest aTest
(testing "Simple test"
(is (= 1 1))))
I would like an output like (formatting is arbitrary):
Testing <namespace>
Passed: aTest -> Simple test
Ideally, the passed test would also be color coded.
I looked at a few libraries, including lein-test-refresh and humane-test-output, but didn't see what I needed. The other option looks like to rewrite the report function in clojure.test, but I'd like to avoid that if possible.
I think you'll have to write it yourself. If you would like an example of how to leverage the existing deftest into a custom macro, here is an example from the Tupelo library that automatically picks a "name" for the deftest group based on the line number:
(defmacro dotest [& body]
(let [test-name-sym (symbol (str "dotest-line-" (:line (meta &form))))]
`(clojure.test/deftest ~test-name-sym ~#body)))
(dotest
(is (= 5 (+ 2 3)))) ; works!
You could just add in a println and voila!
I remember, the Eftest library provides nice colored output when running tests, you may take a look.
Also, the standard clojure.test framework supports adding your own reports. Check the Test report library for the reference.
Probably, when running the tests from your editor or IDE, it could provide the colored output. Here is my Cider-powered Emacs screenshot with the failure report:
I have searched multiple times for an answer to this question, so here is a complete solution building on #ivan-grishaev's hint using Test Report:
Test Report hooks into clojure.test to provide custom reporters that are then being run with every event occuring through a test run. Those events are passed as maps called "messages". The minimal example just appliesclojure.pprint/pprint to the messages, but this only gets you so far. Here is a bit more code to give you a feel how to write custom reporters. The indenting-reporter indents test namespaces, deftests and testing vars, and lists them all independent of test outcome.
Create a file like this in your project:
(ns my.own.test-reporter
(:require [clojure.pprint :refer [pprint]]
[clojure.test :as ct]
[clojure.core.match :refer [match]]))
(defn simple-reporter [msg]
(pprint msg))
(defn indenting-reporter [msg]
(match (:type msg)
:begin-test-ns (println (str "Testing " (:ns msg) "\n"))
:begin-test-var (println (str " " (-> msg :var meta :name)))
:pass (do (println (str " " (-> msg :context first) " :pass"))
(ct/inc-report-counter :pass))
:fail (do (println (str " " (-> msg :context first) " :fail"))
(ct/inc-report-counter :fail))
:error (do (println (str " " (-> msg :context first) " :error"))
(ct/inc-report-counter :error))
:end-test-ns (println)
:end-test-var ()
:summary (pprint msg)
:else (pprint msg)))
and then use it in the :test profile of your project.clj:
:injections [(require '[my.own.test-reporter :as tr])]
:test-report {:reporters [tr/indenting-reporter]}
You could now go on an add color to the outputs.

How can I display the definition of a function in Clojure at the REPL?

I'm looking for the ability to have the REPL print the current definition of a function. Is there any way to do this?
For example, given:
(defn foo [] (if true "true"))
I'd like to say something like
(print-definition foo)
and get something along the lines of
(foo [] (if true "true"))
printed.
An alternative to source (which should be available via clojure.repl/source when starting a REPL, as of 1.2.0. If you're working with 1.1.0 or lower, source is in clojure.contrib.repl-utils.), for REPL use, instead of looking at functions defined in a .clj file:
(defmacro defsource
"Similar to clojure.core/defn, but saves the function's definition in the var's
:source meta-data."
{:arglists (:arglists (meta (var defn)))}
[fn-name & defn-stuff]
`(do (defn ~fn-name ~#defn-stuff)
(alter-meta! (var ~fn-name) assoc :source (quote ~&form))
(var ~fn-name)))
(defsource foo [a b] (+ a b))
(:source (meta #'foo))
;; => (defsource foo [a b] (+ a b))
A simple print-definition:
(defn print-definition [v]
(:source (meta v)))
(print-definition #'foo)
#' is just a reader macro, expanding from #'foo to (var foo):
(macroexpand '#'reduce)
;; => (var reduce)
You'll want to import the repl namespace, and use the source function from it:
(ns myns
(:use [clojure.repl :only (source)]))
(defn foo [] (if true "true"))
(source foo)
=> (foo [] (if true "true"))
nil
Though this wouldn't work in the REPL, only where the function is defined in a .clj file on the classpath. Which doesn't answer your question, then: you'd need to have a defn that stores, in the metadata of the fn it defines, the source of the function. Then you'd write a function that recalls that bit of metadata. That shouldn't be terribly difficult.
Clojure doesn't have a decompiler, so that means there's no way to get at the source of an arbitrary function unless it was a defn loaded from disk. However, you can use a neat hack called serializable-fn to create a function that has its source form stored in its metadata: http://github.com/Seajure/serializable-fn
The defsource answer is very similar to this, but this solution works with arbitrary fns, not just top-level defns. It also makes fns print prettily at the repl without a special printing function.
In clojure 1.2's REPL, the source function is immediately available. You can use it this way:
$ java -cp clojure.jar clojure.main
Clojure 1.2.0
user=> (source slurp)
(defn slurp
"Reads the file named by f using the encoding enc into a string
and returns it."
{:added "1.0"}
([f & opts]
(let [opts (normalize-slurp-opts opts)
sb (StringBuilder.)]
(with-open [#^java.io.Reader r (apply jio/reader f opts)]
(loop [c (.read r)]
(if (neg? c)
(str sb)
(do
(.append sb (char c))
(recur (.read r)))))))))
nil
user=>
A few other functions are also automatically imported into the REPL's user namespace from the clojure.repl library. See the API doc here.
However, as pointed out in other answers here, you can't use source as is to print back functions you have defined in the REPL.
I asked exactly this question on the Clojure mailing list recently and the answers included overriding parts of the REPL to stash the input (and output) away for future reference as well as an override of defn to store the source in metadata (which you could then easily retrieve in the REPL).
Read the thread on the Clojure mailing list