Recent findings on Clojure testing

These days I’m spending time looking into testing in Clojure. I’ve been writing my share of test cases in PHP at work. There we have several tests “freezing” time or mocking services. Both practices are common and something worth learning for Clojure.

Freeze time

Personally I often find it easier to reason about/test the code when providing a reference date to the function. The “new” Date/Time introduced in Java 8, as well as the Clojure wrappings, are both very well crafted. Even though I’m not a big fan of “freezing” time, it has its uses, and I was very delighted to find how easy it is to achieve in Clojure:

(ns my-ns.core
  (:require [java-time :as time]))

(defn >10-secs-ago
  [my-instant]
  (time/after? my-instant (time/plus (time/instant) (time/seconds 10))))


(ns my-ns.core-test
  (:require [clojure.test :as t]
            [java-time :as time]
            [my-ns.core :as sut]))

(t/deftest >10-secs-ago
  (t/testing "More than 10 seconds ago check on instant that is"
    ;; The clock is mocked using milli seconds
    ;; 1549411200000 = 2019-02-06T00:00:00.000Z
    (time/with-clock (time/mock-clock 1549411200000)
      (t/testing "less than 10 seconds ago"
        (t/is (false? (sut/>10-secs-ago (time/instant 1549411200999)))))
      (t/testing "exactly 10 seconds ago"
        (t/is (false? (sut/>10-secs-ago (time/instant 1549411210000)))))
      (t/testing "more than 10 seconds ago"
        (t/is (true? (sut/>10-secs-ago (time/instant 1549411210001))))))))

Mount mock

Mount is framework for managing life-cycle and dependencies for an application with runtime state. So far, I’m really impressed with it and I enjoy it over other frameworks trying to solve the same thing.

Testing code that relies on application state had me puzzled for a little while. Some examples I found suggested using start-with, but even though I was able to swap part of the application state, the entire application was mounted. Since I’m only interested in testing parts of the application I wanted to avoid starting or mocking things untouched by the test.

This is how I did it:

(ns my-ns.core
  (:require [mount.core :as mount]))

(mount/defstate sessions
  :start (atom {}))

(defn open-session []
  (let [id (gensym)]
    (swap! sessions assoc id ::open)
    id))

(defn close-session
  [id]
  (swap! sessions dissoc id))


(ns my-ns.core-test
  (:require [clojure.test :as t]
            [mount.core :as mount]
            [my-ns.core :as sut]))

(t/deftest open-session
  (t/testing "that session is being registered upon open"
    (let [sessions (atom {})]
      (->
        (mount/only #{#'my-ns.core/sessions})
        (mount/swap {#'my-ns.core/sessions sessions})
        (mount/start))
      (let [session-id (sut/open-session)]
        (t/is (contains? @sessions session-id)))
      (mount/stop))))

(t/deftest close-session
  (t/testing "that session is being deregistered upon close"
    (let [session-id (gensym)
          sessions (atom {session-id :sut/open})]
      (->
        (mount/only #{#'my-ns.core/sessions})
        (mount/swap {#'my-ns.core/sessions sessions})
        (mount/start))
      (sut/close-session session-id)
      (t/is (not (contains? @sessions session-id)))
      (mount/stop))))

I’m sure the only, swap, start and stop can be shortened with a helper function or macro but that will be for another time. I’m wondering if Mount has a smarter way of doing the above, that I just didn’t find yet?

And if you (like a recent version of me) don’t know what SUT means, Wikipedia is our friend. Happy testing.

Sources of inspiration

I find work related inspiration many places, among others, colleagues meetups and conferences. But most inspiration comes while purposeless roaming the internet. I’ve always been interested in more that just writing the code for the software. Whether it be participating in meetings and discussions that would help me better understand the business. Gathering data to predict how a UI should be formed for optimal user experience. Learning how to avoid making poor software design decisions that would bring the nice people in operations in trouble. But also the softer things like how culture and circumstances affects us as developers and individuals.

Prior getting the responsibility for a team, all the above would just be archived mentally as “work/software development”. These days, stuff related to work culture and people have earned its own archive label. Suddenly these things have a slightly different meaning to me.

Before I was laughing when seeing/reading things like these (and I still do):

Now failing to do my job properly… the joke will be on me.

To get to the core of the matter. I would like to share the following links because they either gave me food for thought or just solidified my view on matters:

About cutting corners

It takes time to understand a problem, because before you can fully understand it, you need to also understand its context. As a code base grows, depending on how well the code is structured, the context in which you need to understand the problem can (and often will) grow.

When a problem or its context is misunderstood there is a tendency to oversimplify the problem. I’m all for finding a simple and elegant solution but not at the cost of correctness. Oversimplified solutions will not be able to handle all special cases, and special cases lead to crashes or data corruption… or both. This in turn leads to maintenance and clean up by the programmer which I would much rather have coding on this next big thing.

The available time to implement a solution is not only challenged by a push for quick deliveries but also a lack of respect that creating software is actually hard. I’ve experience this lack of respect from all involved parties (including the programmer).

Even though I strive to “do things right”, I also think it is okay and often necessary no to. But it should be a conscious decision.

I.e. making sure to handle two use cases (corner cases) will increase development time but at the same time those a very unlikely to happen or if they happen they are very easy to correct manually. If someone makes a conscious decision that these cases should be handled outside the software, then it is okay.

It is NOT okay (and very short sighted) when the pressure doesn’t allow collecting the necessary information to make that decision.

So by all means cut corners - but only do so together with proper risk assessment.

What makes software stable

Having been given a new area of responsibility as team lead inspired me to think about aspects of coding beyond just typing it.

I’ve experienced we where chasing our own tail. Trying to close issues “fast” and hurry on to the next in line. But something wasn’t working. Every time we changed a comma in one end, something in the other end would break horribly. Bug fixing was feeling like killing a hydra. I started blaming the “fast” way of doing things.

I needed to figure out what was wrong with our approach and transition into one that would result in “making stable software”. My gut feeling told me that we needed to become better at “decoupling” and “breaking the code into smaller pieces”.

But I was missing the direct link between my gut feeling and how it would translate into “stable software” until I saw a tweet which brought the things together:

Source @frankvilhelmsen

one of the most important quality parameters for stable code is that it not change too much - apart from the essential bugs of course #hint

Okay I could easily follow the logic: Code that doesn’t change much, is usually a sign of stable code (why change it, if it works - right?).

The solution would be to write code that doesn’t need to be changed in the first place, and when “decoupling” and “breaking code into smaller pieces” are done correctly, it does exactly that. Code impacted by changes is greatly reduced.

Example:

Imagine a piece of software consisting of a single function. Now every time a change is made (a bug is fixed or a feature is implemented) in that function 100% of the system is changed. If instead it was possible to split this function up into 3 functions then having to change a function would only mean that 33% of the system was changed.

33% beats 100% every time.

And before someone says it I would like to entertain the possibility that the exact same code from the 3 functions was gathered in 1 function. What would be the difference?

The computational results of the two pieces of code right then and there would of course be the same. But the fact that the code isn’t already split up is in my experience a sign of too tightly coupled code. Also having the code split up usually makes it both easier to test and reason about (win/win).

Having to change a long chain of functions to fix a bug or implement a new feature is usually ALSO a sign of too tightly coupled code. Just to point out that having a lot of functions doesn’t necessarily decouple the code :-)

Anyways… for identifying both what and how to “decouple” and “break down” code, I use my “hands on” experience from functional programming and async systems. Also reading about S.O.L.I.D. principles is i good source of inspiration, though nothing beats “hands on”.

Inspect Laravels query builder output

When learning something new (in this case Laravel and it’s ORM Eloquent) it is always nice to be able to “look behind the curtains” to see what actually happens. This both help you understand the internals of the things you are using and can sometime make bug squashing a lot easier.

I wanted to be able to see the SQL that Eloquents query builder was producing, because SQL is something I’m fairly proficient with.

I found several questions and answers on different approaches on StackOverflow but one approach stood out for me: Using Laravels internal events.

Every time Laravel does anything through a database connection an event i fired with the prepared statement and its bindings. But creating SQL queries from this still required some manual labor because I needed to replace all the question marks with the binding in order.

So to close this gab further I had the prepared SQL and bindings crunched by sprintf before writing it to a log file or stdout, like so:

\Event::listen(
    'illuminate.query',
    function($query, $params, $time, $conn)
    {
        $sql = str_replace('?', '%s', $query);
        $preppedSql = call_user_func_array('sprintf', array_merge([$sql], $params));

        echo $preppedSql . "\n"; // or write it to a log file
    });