Search code examples
clojuretddmidje

In Clojure and Midje, how can I write prerequisites for an indirect call?


In the following code, I'd like to test the foo function before implementing the bar function.

(unfinished bar)

(def tbl {:ev1 bar})
(defn foo [ev] ((tbl ev)))

(fact "about an indirect call"
  (foo :ev1) => nil
  (provided
    (bar) => nil))

But Midje says:

FAIL at (core_test.clj:86)
These calls were not made the right number of times:
    (bar) [expected at least once, actually never called]

FAIL "about an indirect call" at (core_test.clj:84)
    Expected: nil
      Actual: java.lang.Error: #'bar has no implementation,
      but it was called like this:
(bar )

I thought that 'provided' couldn't hook the bar function because the foo didn't directly call the bar. But I also found if I changed the second line like this:

(def tbl {:ev1 #(bar)})

then the test succeeded.

Is there any way to succeed for the first version?

Thanks.

PS: I'm using Clojure 1.5.1 and Midje 1.5.1.


Solution

  • provided uses a flavour of with-redefs to alter the root of a var. When defining tbl you already dereference the var #'bar, prompting tbl to contain the unbound value instead of a reference to the logic to be executed. You cannot provide replacements for already evaluated values is what I'm trying to say.

    Similarly:

    (defn x [] 0)
    (def tbl {:x x})
    (defn x [] 1)
    ((:x tbl)) ;; => 0
    

    What you want is to store the var itself in tbl:

    (defn x [] 0)
    (def tbl {:x #'x})
    (defn x [] 1)
    ((:x tbl)) ;; => 1
    

    Same for your tests. Once you use (def tbl {:ev1 #'bar}), they pass.