Skip to content
marick edited this page Feb 15, 2013 · 14 revisions

Testing code that works with mutable state often requires that you change that state before or after a fact or individual prediction. Midje's mechanism for doing that is too baroque, and it will be changed in the future. It's best if you use only features that will translate easily to the (likely) new mechanism. That will save you trouble when the current mechanism is deprecated. To that end, only such features are described here. If you want all the details, the old documentation is still available.

Midje can execute code before facts, after facts, and around facts.

Setup

We'll just use an atom to represent state:

(def state (atom nil))

Here is an expression that sets the atom to 0 before every fact in its scope:

(against-background [(before :facts (reset! state 0))]
  (fact ...)
  (fact ...)
  ...)

There was thought behind my choice of the word "background", but it was not good thought, so you might as well consider against-background an arbitrary token. before can take arguments other than :facts, but I recommend you not use them, and they're not documented here.

Multiple forms

Annoyingly, before only accepts a single form. If you give more than one, you'll get an error message something like this:

Midje could not understand something you wrote: 
  `(before :facts (println "Before code") (reset! state inc))`.
  `before` has two forms: `(before <target> <form>)` and `(before <target> <form> :after <form>).

To have multiple forms, you'll have to use do:

(against-background [(before :facts (do (println "Before code")
                                        (reset! state inc)))])
   (fact...))

Sorry about that.

Nesting

If nested facts both have before forms, they are evaluated in outside-in order for each nested fact. Consider the following:

(facts swap!
  (against-background [(before :facts (reset! state 0))]
    (fact "uses a function to update the current value"
      (swap! state inc)
      @state => 1)

    (fact "that function can take additional args"
      (swap! state - 33)
      @state => -33)

    (fact "swap returns the new value"
      (swap! state inc) => 1)))

The output is this:

outer setup
starting outer fact
  going to check inner fact
outer setup                   ;; note that the outer setup gets done *again* for the inner fact
  inner setup
  here I am in the inner fact
  done checking inner fact
finishing outer fact

This is likely The Wrong Thing, and the new version will probably not do it.

Teardown

If you need code executed after facts, use after:

(against-background [(after :facts (swap! state dec))]
  (fact ...)
  (fact ...))

Like before, after takes only one form to evaluate.

Ordering

Nested after expressions are executed in inside-out order, the opposite of before. Consider the following:

(against-background [(before :facts (println "outer in"))
                     (after :facts (println "outer out"))]
  (against-background [(before :facts (println "  inner in"))
                       (after :facts (println "  inner out"))]
    (fact (+ 1 1) => 2)))

Here's what's printed:

outer in
  inner in
  inner out
outer out

Wrapping facts

It's not uncommon for Clojure libraries to provide wrapping macros that don't give you direct access to state. Consider this example of product code:

(with-telemetry-from (launch "sr81" ...)
  (set-rocket-countdown! 10))

If you want multiple tests of the results of a particular launch configuration, you might be faced with considerable awkward duplication of code. (Each fact would have to describe the same configuration.)

also show an example of let

Repl support

Clone this wiki locally