Skip to content
jrantanen edited this page Dec 28, 2012 · 9 revisions

This tutorial shows Midje's most basic use. It introduces the ideas of "facts" and "checkers".

Before running the tutorial, perform the three Getting Started steps.

Getting started

Begin by creating a new project:

$ lein new checkers
Created new project in: /Users/marick/tmp/checkers
Look over project.clj and start coding in checkers/core.clj
$ cd checkers

Despite Leiningen's suggestion, we won't start coding just yet. Instead, we'll use lein midje to run any tests that might be predefined for us:

2487 $ lein midje
>>> Output from clojure.test tests:

FAIL in (replace-me) (core.clj:6)
No tests have been written.
expected: false
  actual: false

>>> clojure.test summary:
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
>>> Midje summary:
All claimed facts (0) have been confirmed. 

lein midje runs tests written both in Midje and the <snark>legacy</snark> clojure.test format. What the above tells us is that new Leiningen projects come with a single clojure.test test that fails. Let's turn that into a Midje test that fails.

The first step is to add Midje to the project.clj file in the project root directory:

(defproject checkers "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.3.0"]]
  :dev-dependencies [[midje "1.4.0"]])     ; <<<<====

Then you can ask Leiningen to download dependencies:

$ lein deps
Copying 1 file to /Users/marick/src/Midje-quickstart/checkers/lib
Copying 11 files to /Users/marick/src/Midje-quickstart/checkers/lib/dev
$ ls lib/dev/midje*
lib/dev/midje-1.4.0.jar

Edit the test file in test/checkers/test/core_test.clj and change the namespace declaration to use Midje:

(ns checkers.test.core
  (:use [checkers.core])
  (:use [midje.sweet]))  ; Used to be (:use [clojure.test])

That's all the setup that's required.

Facts

Next, replace this test:

(deftest replace-me ;; FIXME: write
  (is false "No tests have been written."))

... with a claim about arithmetic that's illustrated by an example:

(fact "addition has a unit element"
  (+ 12345 0) => 12345)

When you run that, you should see the following:

$ lein midje
All claimed facts (1) have been confirmed. 

(Strictly, the fact about arithmetic hasn't been confirmed, just the example. The terminology has shifted over time, and the messages haven't kept pace.)

Knowing that something you've claimed true actually is true – well, that's not so exciting. It's more of an intellectual rush to discover that what you think is true isn't. Let's simulate that by misunderstanding arithmetic:

(fact "addition is the same as multiplication"
  (+ 0 0) => 0
  (+ 2 2) => 4
  (+ 1 1) => 1)

You should see this error message:

2504 $ lein midje

FAIL "addition is the same as multiplication" at (core.clj:9)
    Expected: 1
      Actual: 2
FAILURE: 1 fact was not confirmed. (But 2 were.)

Time to rethink your worldview!

Checkers

In something like this:

(fact "addition has a unit element"
  (+ 12345 0) => 12345)

You can read the => token as "is", so the example says "12345 plus zero is 12345".

In general, Midje evaluates the left-hand side of the example to get a value, which it then compares to the right-hand side. It doesn't use ordinary equality (=), though, but a kind of extended equality that's more useful for testing. For example, you can compare a string to a regular expression:

(fact "matching"
  "O wad some Pow'r the giftie gie us. To see oursels as ithers see us!"
  => #"giftie")

The string isn't equal to the regular expression, but it matches it, or "checks out" when compared to it.

Importantly, the left-hand side of an example can be compared to a function. That looks like this:

(fact
  (+ 1 1) => even?)

Read this as "one plus one is even". Mechanically, what happens is that the left-hand side is evaluated and passed to the function on the right-hand side. If that function returns a "truthy" value (anything but false or nil) the example checks out.

Midje comes with a collection of checkers that are often useful for testing. For example, suppose that you want to claim that the result of a function is a collection that contains the number 5. You could write that like this:

(defn function-that-returns-a-collection []
  [4])

(fact
  (some #{5} (function-that-returns-a-collection)) => truthy)

truthy is a checker that succeeds if the left-hand side is anything other than false or nil. In this particular case, the left-hand side will be nil, so lein midje will print this:

FAIL at (core.clj:10)
Actual result did not agree with the checking function.
        Actual result: nil
    Checking function: truthy
FAILURE: 1 fact was not confirmed. 

That's fine, but it reads poorly. So there's a checker that's more clear:

(fact
  (function-that-returns-a-collection) => (contains 5))

The result is a little more "chatty":

FAIL at (core.clj:10)
Actual result did not agree with the checking function.
        Actual result: [4]
    Checking function: (contains 5)
    The checker said this about the reason:     <=== Sometimes more detail is printed
        Best match found: []

In this particular case, the "best match found" is not so helpful. It might be in something like this:

(fact
  [1 2 4 5] => (just [1 2 3 4])) ; `just` requires an exact match
FAIL at (core.clj:10)
Actual result did not agree with the checking function.
        Actual result: [1 2 4 5]
    Checking function: (just [1 2 3 4])
    The checker said this about the reason:
        Best match found: [1 2]
FAILURE: 1 fact was not confirmed. 

Summary

The correctness of your program requires that certain facts you assume are true, truly are true. Midje lets you state those facts and illustrate them with examples. When you see those examples check out, you have greater confidence that your program is correct.

Clone this wiki locally