← Back to posts

Translation of clojure.test to JavaScript / Java developers

clojure.test is the unit testing framework. There are various macros that conceptually correspond to functions used in JavaScript / Java testing frameworks you might be familiar with. This is an attempt to "translate" the frequently used syntax, which hopefully will help you when you write your next Clojure test cases.

is

This is like expect(a).toEqual(b) in JavaScript, or assertEquals(expected, actual); in Java. The basic usage is that is takes an arg which needs to evaluate to true.

(is (= 42 (calculate-answer-to-universe))) ;; without description
(is (= 42 (calculate-answer-to-universe)) "it'd better be equal") ;; with description

testing

This is used to organize groups of assertions, similar to test in Jest.

(defn inc-and-multiply [a b]
  (->> [a b]
       (map inc)
       (apply *)))

;; tests
(testing "increments each number before multiplying them"
  (is (= 12 (inc-and-multiply 2 3)))
  (is (= 20 (inc-and-multiply 3 4)))
  (is (= 30 (inc-and-multiply 4 5))))

are

Clearly, the example above is basically repeating itself with 3 groups of expected value versus input. We can simplify it by using are macro. This is similar to JUnitParams.

(deftest inc-and-multiply-test
  (are [expected a b] (= expected (inc-and-multiply a b))
    12 2 3
    20 3 4
    30 4 5))

;; run a single test, evaluates directly in REPL
(run-test inc-and-multiply-test)

deftest

This is a higher level abstraction of a group of tests. Normally you'd find a few testing inside a deftest.

(deftest send-todoist-request-check
  (testing "throws exception when api token is missing"
    (is (thrown? IllegalStateException (save (get-todoist nil) 1))))
  (testing "throw exception when payload is invalid"
    (is (thrown? IllegalArgumentException (save (get-todoist mock-api-token) 1)))
    (is (thrown? IllegalArgumentException (save (get-todoist mock-api-token) {:name (rand-str)})))))

As you have seen, the thrown? above is an implementation of assert-expr multimethod. This is similar to assertThrows in Junit. More importantly, given it's a multimethod, it means we can write our own assertion expressions here. You can find a detailed blog post about this here. This is similar to writing your own assertion in Hamcrest.

use-fixtures

This is similar to before, beforeEach, after and afterEach, controlled by the keyword passed in. Here is the basic usage.

(defn before-all-step []
  (println "before all step"))

(defn after-all-step []
  (println "after all step"))

(defn before-each-step []
  (println "before each step"))

(defn after-each-step []
  (println "after each step"))

(defn whole-suite-fixture [f]
  (before-all-step)
  (f)
  (after-all-step))

(defn each-fixture [f]
  (before-each-step)
  (f)
  (after-each-step))

(use-fixtures :once whole-suite-fixture)
(use-fixtures :each each-fixture)

So, what should it print when we run the following test? How many times will before-each-step and after-each-step run?

(deftest my-test
  (testing "testing a"
    (is (= 1 1))
    (is (= 2 2))
    (is (= 3 3)))
  (testing "testing b"
    (is (= 1 1))
    (is (= 2 2))
    (is (= 3 3))))

As it turns out, before-each-step and after-each-step is only run per deftest.

before all step
before each step
after each step
after all step

Ran 1 tests containing 6 assertions.
0 failures, 0 errors.
{:test 1, :pass 6, :fail 0, :error 0, :type :summary}

Alright, that's all for now. Hope it's been helpful. There are still many more inside clojure.test, which you can read in the official documentation.

HomeBlogContactGithubReading