Here is a small part about debugging in kaocha: https://cljdoc.org/d/lambdaisland/kaocha/1.69.1069/doc/8-plugins, which i do not understand.
Is there a way to debug kaocha tests or at least a way to execute a test directly from the REPL, so that i can debug the test?
Don't know about kaocha, but deftest macro just generates ordinary function by the test name passed to it in the test namespace:
(require '[clojure.test :as t])
(require '[clojure.walk :as w])
(w/macroexpand-all '(t/deftest a
(println "before test")
(t/is 1 1)
(println "after test")))
;;=> (def a (fn* ([] (clojure.test/test-var (var a)))))
so, you just call it from anywhere you want, just importing the test namespace:
user=> (ns my-tests)
nil
my-tests=> (require '[clojure.test :as t])
nil
my-tests=> (t/deftest some-test (let [x 101] (println "x is " x) (t/is x 101)))
#'my-tests/some-test
my-tests=> (in-ns 'user)
#object[clojure.lang.Namespace 0x4c98a6d5 "user"]
user=> (my-tests/some-test)
;;=> x is 101
nil
Not a direct answer, but I tried Kaocha & didn't like it as much as the original Leiningen driven tests, especially with the lein-test-refresh plugin. Besides running from the REPL as in the other answer, you can also run either all tests or only one test from the command line.
With the Test Refresh Plugin, the computer will watch your your source for any changes. Upon any editor save, the code will be reloaded & recompiled, then all modified tests will be re-run. The tests are typically completed before your finger has left the <enter> key.
You can see an example of using lein-test-refresh here. Below is an excerpt from the README:
Running Unit Tests with lein test-refresh
IMHO, the lein-test-refresh project provides the best way of doing iterative development in Clojure, re-running unit tests every time you save a source file from the editor.
> lein test-refresh
or make an alias:
alias lctr="lein do clean, test-refresh" # lctr => Lein Clean Test-Refresh
with result:
Testing _bootstrap
-------------------------------
Clojure 1.10.1 Java 13
-------------------------------
Testing tst.demo.core
result => "Hello, World!\n"
Ran 4 tests containing 6 assertions.
0 failures, 0 errors.
Passed all tests
Finished at 07:56:48.252 (run time: 6.709s)
in this instance, the test output pauses after printing the elapsed time, and waits to re-run upon any file change. For example, make a simple change in the namespace demo.core by adding the word "Again!" to the println expression, and watch as the tests are automatically re-run:
...
Testing tst.demo.core
result => "Hello, World! Again!\n"
...
Finished at 07:59:53.863 (run time: 0.034s)
Note that the tests were all re-run in only 34 milliseconds (nearly instantaneous), since the JVM was already started and Clojure itself (plus library code) has already been compiled.
Related
I have defined a Clojure namespace with test functions and want to run them using Leiningen 2.9.1 via lein test.
The test functions are organized hierarchically. If I just run lein test, all the deftest will be picked up, leading to test duplication. For example:
(ns foo.bar.test
(:require
[clojure.test :as t]
[clojure.spec.alpha :as s]
[foo.bar.main :as sut])) ; system under test
(t/deftest test-strip-empty
(t/is
(s/valid? ::sut/a-spec some-value)))
(t/deftest test-strip-several-squares
(t/is
(s/valid? ::sut/a-spec some-value)))
; collect subtests
(t/deftest testcollect-strip
(test-strip-empty)
(test-strip-several-squares))
lein test would run all three deftest entries, thus running test-strip-empty and test-strip-several-squares twice.
The function test-ns-hook can be defined to explicitly call the "top of the test tree".
(defn test-ns-hook []
(testcollect-strip))
If exists, lein test will only call test-ns-hook:
Which is nice!
But once it exists, I cannot ran individual tests anymore.
lein test :only foo.bar.test/test-strip-several-squares
lein test foo.bar.test
Ran 0 tests containing 0 assertions.
0 failures, 0 errors.
Not nice!!
Remove the definition of test-ns-hook and it works:
lein test :only foo.bar.test/test-strip-several-squares
...
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
Tests failed.
Can happyness be maximized by combining both features: leaving test-ns-hook defined and being able to run individual tests?
Don't group your tests like with testcollect-strip. I would call this an antipattern.
You can make individual assertions hierarchical within a single deftest form using the testing macro: https://clojuredocs.org/clojure.test/testing
(deftest t-math
(testing "Arithmetic"
(testing "with positive integers"
(is (= 4 (+ 2 2)))
(is (= 7 (+ 3 4))))
(testing "with negative integers"
(is (= -4 (+ -2 -2)))
(is (= -1 (+ 3 -4))))))
~/expr/demo > lein clean ; lein test
lein test _bootstrap
-------------------------------
Clojure 1.10.0 Java 12
-------------------------------
lein test tst.demo.core
Ran 2 tests containing 4 assertions.
0 failures, 0 errors.
You can also use test selectors to run only a subset of tests:
~ > lein help test
Run the project's tests.
Marking deftest or ns forms with metadata allows you to pick selectors to
specify a subset of your test suite to run:
(deftest ^:integration network-heavy-test
(is (= [1 2 3] (:numbers (network-operation)))))
Write the selectors in project.clj:
:test-selectors {:default (complement :integration)
:integration :integration}
Arguments to this task will be considered test selectors if they are keywords,
otherwise arguments must be test namespaces or files to run. With no
arguments the :default test selector is used if present, otherwise all
tests are run. Test selector arguments must come after the list of namespaces.
A default :only test-selector is available to run select tests. For example,
`lein test :only leiningen.test.test/test-default-selector` only runs the
specified test. A default :all test-selector is available to run all tests.
Arguments: ([& tests])
So, adding metadata to the test definition
(deftest ^:basic-math t-math
(testing "Arithmetic"
(testing "with positive integers"
(is (= 4 (+ 2 2)))
(is (= 7 (+ 3 4))))
(testing "with negative integers"
(is (= -4 (+ -2 -2)))
(is (= -1 (+ 3 -4))))))
And declaring test selector :basics to grab everything tagged with :basic-math in project.clj:
(defproject foo.bar "0.1.0-SNAPSHOT"
...
:test-selectors {:basics :basic-math})
One can now run only the tests tagged with :basic-math via:
~ > lein test :basics
There is another trick to keep in mind. The namespace structure of your test code (dirs/files) doesn't need to match that of your source code. You could have a single source code ns super.calc, but a whole hierarchy of testing namespaces. I prefix them all with a root tst. prefix, which I think leads to a nicer naming structure than sticking a _test suffix on everything:
tst.super.calc
tst.super.calc.add
tst.super.calc.add.int
tst.super.calc.add.int.pos
tst.super.calc.add.int.neg
tst.super.calc.add.float
tst.super.calc.add.float.pos
tst.super.calc.add.float.neg
tst.super.calc.mult
...
So you can get as fine-grained as you desire. Mixing this with lein test selectors allows nearly infinitely fine-grained control.
Also,
Please checkout lein-test-refresh, my favorite way of doing testing in lein
https://github.com/jakemcc/lein-test-refresh
I am having a hard time creating a simple unit test in Clojure using with-redefs for mocking on Windows. The test code, the function I'm about to test and the function to be mocked are all in different namespaces/files:
Function under test:
(ns com.mynamespace.a
(:require [com.mynamespace.b :as b] ) )
(defn afunc [param]
(b/bfunc param))
Dependent b namespace to be mocked out:
(ns com.mynamespace.b)
(defn bfunc [param]
; External call
)
Test code
(ns com.mynamespace.a-test
(:require [com.mynamespace.a :as a]
[com.mynamespace.b :as b] )
(:use [clojure.test]))
(deftest a-tests
(with-redefs [b/bfunc (constantly "dummy")]
(print (a/afunc "test"))
)
)
I think I use with-redefs correctly, because my unit test runs fine on Linux machines (docker container or virtual Ubuntu), but it just does not work when executing/developing them on my Windows dev machine: the with-redefs bindings are not applied and the test wants to make real e.g. http calls, which I'd like to mock. It is the same case if I run lein test, or try executing the test from a REPL through Eclipse CCW.
I know with-redefs has some strange behaviour, but as my test works well on Linux, I guess I miss something, when running this project's test on Windows. I would like to achieve fast feedback loops, when writing tests on my Windows machine.
Do you have any idea what I'm doing wrong?
Thanks,
Andras
Turned out that this issue was specific to a project I'm working on, because of the -Dclojure.compiler.direct-linking=true jvm-opts flag.
After turning off direct linking, my tests work on my Windows dev machine as well. I wonder why they passed on Linux though, but perhaps it was not applied, when running lein test there.
Consider the following unit-test snippet:
(deftest async-test
(testing "Testing some core.async functionality."
(go (is (= (<! (go "val")) "val1")))))
Running the test yields:
Ran 1 tests containing 0 assertions. 0 failures, 0 errors.
FAIL in () (at repl:253:51) expected: (= (<! (go "val")) "val1")
actual: (not (= "val" "val1"))
But this is weird because: (i) there is 1 assertion in this test, yet the test output says there are 0, and (ii) the test statement also says there were 0 failures, even though there was 1 failure.
I suppose this is because the (is...) assertion is in a go block. So my question is, is this the best way to go about unit testing with core.async functionality? Is there some best practice here I'm missing?
This issue is not exclusive of core.async but to all multithreaded code. You need to make sure that the test assertions are run by the thread that starts the tests as that thread also collects and prints the results from all the tests.
In the case of Clojure, you just need to use the blocking <!! operator:
(deftest async-test
(testing "Testing some core.async functionality."
(is (= (<!! (go "val")) "val1")))
In the case of ClojureScript use the async macro. This has plenty of details about testing in ClojureScript
(deftest async-test
(testing "Testing some core.async functionality."
(async done
(go
(is (= (<! (go "val")) "val1"))
(done)))))
I have boot-clj installed and want to be able to edit a .clj file in an external editor and separately have a command line REPL running from which I can call the functions that I change in the .clj file. No special reloading commands should be required.
Another thing is I don't want to have to manually type commands to include namespaces - I would like to just run a script that brings me into the namespace, so I can call existing functions right away.
Name of the file:
C:\dev\my-project\src\my_project\utils.clj
Something of what is inside the file:
(ns my-project.utils
(:require
[clojure.string :as s]))
(defn my-range [start end]
(take (- end start) (iterate inc start)))
I would like to go straight into a REPL and go (my-range 0 3) and see if it produces the result I want.
What's the setup for this? What would the script file I need to run look like?
My current understanding is that the answer will look something like this:
(deftask dev-repl
(set-env! …)
(repl))
at the command line
You can achieve this to some degree at the command line, without creating a build.boot file:
In C:\dev\my_project:
boot -r src repl -n my-project.utils
boot -r src: starts boot with src on the "resource paths", which is the set of directories that will be accessible within the JVM.
repl -n my-project.utils starts a REPL, requires your namespace, and enters it.
While the REPL is running, and after you have edited C:\dev\my_project\src\my_project\utils.clj, you can reload it at the REPL like this:
my-project.utils=> (require 'my-project.utils :reload)
nil
minimal build.boot
Alternatively, you could create the file C:\dev\my_project\build.boot with these contents:
(set-env! :resource-paths #{"src"})
(deftask dev
"Run a development REPL"
[]
(repl :init-ns 'my-project.utils))
Then, in C:\dev\my_project:
boot dev
Which will also start a REPL in your namespace, but requires less command-line configuration as we've performed the configuration in build.boot, which boot will automatically evaluate.
Note: from a Clojure REPL, regardless of build tool, you can require any namespace (as long as it's on the JVM's class path) with the require function and enter it with the in-ns function.
build.boot with automatic reloading
Finally, it's possible to combine features of Boot to achieve a development workflow oriented around automatically reloading code.
In C:\dev\my_project\build.boot:
(set-env! :resource-paths #{"src"})
(require '[boot.core :as core]
'[boot.pod :as pod])
(deftask load-ns
"Loads the my-project.utils namespace in a fresh pod."
[]
(let [pods (pod/pod-pool (core/get-env))]
(core/with-pre-wrap [fileset]
(pod/with-eval-in (pods :refresh)
;; We require indirectly here so that errors from my-project.utils have
;; proper line and column information.
(require 'my-project.load-impl))
fileset)))
(deftask dev
"Watches source code and loads my-project/utils every time code changes."
[]
(comp (watch)
(load-ns)))
In C:\dev\my_project\src\my_project\load_impl.clj:
(ns my-project.load-impl)
(require 'my-project.utils)
In C:\dev\my_project\src\my_project\utils.clj:
(ns my-project.utils
(:require
[clojure.string :as s]))
(defn my-range [start end]
(take (- end start) (iterate inc start)))
(println "In the code!")
(println "(my-range 0 10) = " (my-range 10 20))
Back at the command prompt, type boot dev. You should see some println output, and every time you edit and save the file you should see it again, reflecting any changes you made.
JavaFX 8, Java 1.8.0_31, Windows 7 x64
I have a minimal JavaFX program in Clojure. The (ns...) clause is able to import the required Java packages fine except the classes in javafx.scene.control, such as Button and TextField, etc.
I have to put the import for these after initializing the toolkit. Why can't I import these classes before the toolkit is initialized? I'm not actually creating any objects yet... so I'm guessing JFX is somehow doing something in the background while these classes are imported, requiring the initialization first. Below is my complete lein project (minimized from the actual application where I saw this problem, and without all the nice macros that clean up the JFX syntax):
File project.clj:
(defproject jfx-so "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.6.0"]]
:main jfx-so.core)
File src/jfx_so/core.clj:
(ns jfx-so.core
(:import [javafx.scene Scene]
[javafx.scene.layout BorderPane]
[javafx.stage Stage]))
(defonce force-toolkit-init (javafx.embed.swing.JFXPanel.))
;; For some reason the following must be imported after initting the toolkit
(import [javafx.scene.control Button])
(defn -main [& args]
(javafx.application.Platform/runLater
#(doto (Stage.)
(.setScene (Scene. (BorderPane. (Button. "Hello"))))
(.show))))
Thanks! :)
I haven't had a problem with this. Perhaps it has to do with your defonce?
I do my imports first. But I do make sure to init the FX-envoronment before instanciating any FX-classes. So after your -main-method I would put:
(defn -main [& args]
;;body here
)
;; initialze the environement
(javafx.embed.swing.JFXPanel.)
;; ensure I can keep reloading and running without restarting JVM every time
(javafx.application.Platform/setImplicitExit false)
;; then
(-main)
Hope this helps.