26 Mar 2020 · Semaphore News

    Testing Clojure With Expectations

    3 min read

    Clojure is shipped with clojure.test — a library with basic features for writing tests. However, there are a few alternatives that aim to make writing tests more pleasant or more suitable for BDD. Expectations by Jay Fields is one of them, described as “a minimalist’s unit testing framework” with the slogan “adding signal, removing noise”.

    Expectations setup

    The easiest way to get started is to add Expectations and lein-expectations to your project.clj:

    (defproject expectations-playground "0.1.0-SNAPSHOT"
      :description "Playground for exploring Expectations"
      :license {:name "Eclipse Public License"
                :url "http://www.eclipse.org/legal/epl-v10.html"}
      :dependencies [[org.clojure/clojure "1.6.0"]
                     [expectations "2.0.9"]]
      :plugins [[lein-expectations "0.0.8"]])

    After that, you can run tests with lein expectations.

    Expectations also integrates well with several editors and development environments, such as Emacs and IntelliJ. More information about installation and setup can be found in the library documentation.

    Adding signal, removing noise

    A simple example that compares clojure.test and Expectations already reveals few interesting details:

    ; clojure.test
    (deftest equality-test
      (testing "Is 'foo' equal 'fooer'"
        (is (= "foo" "fooer"))))
    ; expectations
    (expect "foo" "fooer")

    Running the test with clojure.test gives:

    While running the test with Expectations gives:

    We already see Expectations delivering on the slogan “adding signal, removing noise”. The test is shorter, but it gives us more informations in a nicer way. Output is colored by default, format is a bit easier on eyes and it’s more precise about the failure — it says what’s different about strings. It also shows how much time the test took to run, which can be useful when optimizing tests.

    Minimal and consistent syntax

    It’s interesting to see how minimal and consistent the Expectations syntax is. At first glance, there is not much besides expect. It can get you a long way:

    (expect 2 (+ 1 1))
    (expect "foo" (str "f" "o" "o"))
    (expect [1 2 3] (conj [1 2] 3))
    (expect {:a 1 :b 2} (assoc {:a 1} :b 2))
    (expect #"Expect" "Expectations")
    (expect empty? [])
    (expect 3 (in [1 2 3]))

    Even more signal

    Expectations really shines when it comes to testing collections as it tests not only equality, but also contents of collections:

    Even less noise

    Expectations tries aggressively to remove noise from test output. For example, it trims long stack traces, leaving only the important part.

    Example stack trace using clojure.test:

    This is the equivalent stack trace using Expectations:


    Expectations certainly delivers on promise “more signal, less noise”. But the library also provides a few additional tricks that are not covered here — like testing side effects and freezing time. For more informations, visit the Expectations website.

    Leave a Reply

    Your email address will not be published. Required fields are marked *