- tl;dr
- What else, if not JUnit or Spock?
- Running clojure.test using Leiningen
- Implementing the Tests in clojure.test
- Running the tests
tl;dr
We demonstrate Clojure’s support for boiling down code to its very essence. Download the Leiningen sample setup github.com/JohannesFKnauf/regex-tdd-parameterized-clojure.test-example and start playing.
What else, if not JUnit or Spock?
We started with a blog article about testing regular expressions with JUnit 4 parameterized tests. We showed one improved variant for testing the exact same thing in a followup blog article about improving expressiveness and readability using Spock . In this last part of this series, we will demonstrate the same in Clojure.
The native build tool for Clojure is Leiningen. Clojure ships “batteries included” with a test library named clojure.test
.
Running clojure.test using Leiningen
Install Leiningen and fire up a test run. In doubt, use the default way. Alternative mechanisms you might want to look at are
- SDKMAN!,
- your operating system’s native package repository (for Ubuntu 18.04 this is package Leiningen in version 2.8.1) or
- the Clojure docker image from Docker Hub.
After installing we expect you to have a way of calling lein
like this:
Implementing the Tests in clojure.test
For JUnit 4 we needed special parameterized test annotations. Spock improved this by providing a special test syntax using compile-time AST transformations. In clojure.test
we do not need any of this. We do not need special syntax. We do not need sample tables. We do not need frameworks or bigger libraries. We just express our intent – all the details hidden in plain sight.
The LISP way lets us focus on expressing the essence behind the tests in an almost natural language ({ insert random rant about vices and virtues of parentheses and prefix syntax here }
resp. (random-rant (and vices virtues) (and parentheses prefix-syntax))
). Some people tend to call it an embedded Domain Specific Language (DSL) and claim that the LISP community initiated the entire DSL philosophy a long time before it was hailed as DSL. But writing concise code in Clojure comes so natural, that it feels wrong to use such a magniloquent term.
Where do we end up?
Again, I want to point out the special beauties of this piece of code, as compared to the Spock and JUnit variants:
- Instead of interpreting a true/false flag from the test tuples, we just define proper functions and use them directly in our test case descriptions.
isMatchExpected = true
becomes(is (matching ...) ...)
.isMatchExpected = false
becomes(is (not-matching ...) ...)
. - Clojure’s
let
provides light-weight lexically scoped symbol definitions. We can keep our helper functions well-contained in our scope: 1 line each, no leaking. - The higher order functions
partial
andcomp
enable us to create a pointfree feeling when phrasing the test functions. - Like Groovy’s
/ ... /
construct, Clojure provides syntax sugar for regular expressions with the#" ... "
reader macro.
Running the tests
No surprises. Nothing left to add. Have fun focussing on productivity!
Post header background image by Peter H from Pixabay.