This is a weblog about computing, culture et cetera, by . Read more.

Revisiting Clojure testing

Two years ago I wrote about the Clojure test runner of my dreams. Back then, I asked for a Clojure test runner that would support clojure.test and that would have the following features:

Let’s see where we are now.

After my post, Eftest soon got all the features. It’s a great library and while the included Leiningen plugin is quite rudimentary, bat-test offers a feature-rich wrapper for use with Leiningen and Boot.

When Arne Brasseur announced that he is developing Kaocha, I didn’t see much point in a new test runner. However, I was working a new project that used tools.deps as the dependency management tool. Since bat-test does not have a clj -m -compatible version, I decided to give Kaocha a go.

After using Kaocha for a couple of months, I have to admit that Arne has created a something worthwhile. Kaocha offers test running with all the above-mentioned features and more (e.g. watcher, Cloverage integration) in one coherent, well-documented package. Furthermore, Kaocha’s design allows easy extensions. For example, it was super-easy to create a plugin that toggles on Orchestra instrumentation.

If you’re looking for a new test runner, definitely check out Kaocha.

Side-note: Arne’s work on Kaocha has been funded by Clojurists Together. Their funding has paid for a number of improvements in Clojure projects you’re most likely using. The money comes from individual and corporate sponsors. It seems like a great way for Clojure-using companies to fund work on the tools that their developers use. I’m happy that Metosin has been a sponsor since the beginning and I’m hoping to see more companies on the member list.

What’s next?

Test runners are good now. Does this mean that the Clojure testing landscape is perfect now? Well… I see at least two areas of improvement.

ClojureScript unit testing. Doo (which I co-maintain) is tricky to set up, I’ve had a number of problems with boot-cljs-test, and using Karma directly is a lot of work. Getting my list of dream features to work is possible but tedious.

Luckily there are two new developments: Figwheel Main has built-in unit testing support and Kaocha has kaocha-cljs. Both look promising. This is what I’m most excited about Kaocha – I’m hoping that Kaocha manages to bring the same turn-key experience to ClojureScript that it already has for Clojure.

Assertion libraries. In clojure.test the assertion are written with the is macro, which isn’t very expressive. The main selling point of Midje was its powerful syntax for writing assertions. Unfortunately that power came with the cost of a complex implementation.

Apart from writing your own predicates, what are the current options? I’m aware of testit (my go-to choice), iota, and matcher-combinators. Each of them is significant improvement over is macro, but I don’t love any of them. I guess I need to come up with a list of features for the assertion library of my dreams!

Yearnote 2018

It’s time to look back at 2018 and talk about me.

On being a professional

The biggest thing for me personally was finishing my master’s thesis and graduating as a Master of Science. I’m glad it’s finally done. After graduating I continued working at Metosin as a software developer. In autumn, I joined Metosin’s board of directors.

At work, I took more responsibility on project management. It felt meaningful even if it always wasn’t fun. In general, I feel like I’ve made more mistakes lately. I reckon this is a good thing: either my job has become more challenging or I’ve become better at recognizing mistakes. Both mean more learning.

Here are some things I learned from, other than making mistakes:

On having a life outside work

These were fun:

Some cool cultural works:

What about my plans for 2019?

While 2018 was a pretty okay year for me, I know it was a hard year for a lot of people both on the personal and the societal level. Frankly, I’m not feeling optimistic about the politics. It will get worse before it gets better.

Finally, a year ago I wrote this:

I can’t believe it’s 2018 and Juha Sipilä’s cabinet still hasn’t fallen apart.

Unfortunately it’s 2019 and Sipilä’s cabinet still hasn’t fallen apart, but at least the parliamentary elections are coming up in April.

How I use tap>

A shadow against a bridge pillar on a rock.

One of the new features in Clojure 1.10 is tap. The changelog describes it as follows:

tap is a shared, globally accessible system for distributing a series of informational or diagnostic values to a set of (presumably effectful) handler functions. It can be used as a better debug prn, or for facilities like logging etc.

tap> sends a value to the set of taps. Taps can be added with add-tap and will be called with any value sent to tap>. The tap function may (briefly) block (e.g. for streams) and will never impede calls to tap>, but blocking indefinitely may cause tap values to be dropped. If no taps are registered, tap> discards. Remove taps with remove-tap.

I’m already using it as a better debug prn! I’m using Cursive and I connect to a REPL launched by Boot. With my setup, (prn :DEBUG value) has two potential downsides.

  1. The output may go either to the Boot terminal or to the Cursive IDE depending on the code path.
  2. The output is not pretty-printed.

Tap allows me to solve both problems. I want my debug prints to always appear in Cursive’s REPL, so after starting the REPL, I add a tap handler by running this command:1

(add-tap (bound-fn* puget.printer/cprint))

Here bound-fn* ensures that the output goes to Cursive and not to the terminal. Puget is the pretty-printer I’m used to, but you can replace it with your favorite printer. If you do not want to add new deps, you can use clojure.pprint or even plain old prn:

(add-tap (bound-fn* clojure.pprint/pprint))
(add-tap (bound-fn* prn))

Now when I want to debug-print something, I do (tap> "hello world"). Since both tap> and add-tap are in clojure.core, I don’t need to require anything. I can just tap> away.

Another debugging trick is to store the tapped value in an atom. I’ve used this only once so far, but it was pretty handy. Setup:

(def debug-a (atom nil))
(add-tap #(reset! debug-a %))

Now I can tap> an intermediate value in the middle of some complicated code and then poke at it in the REPL via @debug-a. Ideally you’d use a debugger, but if you are in hurry, maybe tap is enough.

  1. I don’t know how to do this automatically. If somebody knows, please tell me.

For more posts, see archive.