An idea about testing inner functions in Clojure
While working on the “sweet” interface for Midge, I wrote this function:
metavar?
and form-branch?
are only useful within this function. I would have preferred to write it like this:
I didn’t because I wanted those two functions tested before I relied on them. So I need a format for testing inner functions. I’ve sketched out a format and done (by hand) the transformation required to make it work.
I’ll start explaining it with this simple example:
Before dealing with the daunting complexity of multiplication, I want to test summer
with something like this:
(I’m using the Midje sweet notation here. Read it as “It’s a fact that (within (outer 1 2))
, (summer)
produces 3.”)
To make this work, I’d redefine the defn
macro for the duration of a test and have it produce a little extra metadata:
I’m stashing away a function derived from summer
. It creates the same lexical environment that outer
does, and returns a function to call. Here’s the macro that would expand a within
, together with a sample expansion:
The expanded form is a little opaque, so here are the three steps:
- Retrieve the environment setting function from
outer
’s metadata. - Call it with the
outer
arguments. - Within that environment, call
summer.
What if a later inner function uses a previously-defined one? Like this:
One option would be to drag the earlier parts of the let
into the metadata:
In that case, the test would look like this:
This test is a little not-thrilling because it’s clearer what multiplier
does if you can see how it relies on summer
. That could look like this:
However, dragging the previous let
clauses into the metadata has to be done anyway (in case non-function values are bound), so I’d be inclined not to gild this lily.
Creating the metadata wouldn’t be too hard in the common case where the let
is the outermost form in the function’s definition. I doubt I could be persuaded to care about other cases.
August 3rd, 2010 at 7:33 pm
[…] Exploration Through Example » Blog Archive » An idea about testing inner functions in Clojure (tags: clojure macros bindings) […]
August 4th, 2010 at 1:32 am
[…] inner functions in #clojure (here, via @marick) — Brian Marick is working on Midge, a mocking library for Clojure. This post a […]
August 6th, 2010 at 12:26 am
[…] – Measuring Up: Authors note: I wrote this article in 2002. At that time, Agi.. RT @marick – An idea about testing inner functions in Clojure: While working on the “sweet….Big banks need IT reform almost as badly as regulatory change RT @estherderby – Six Ways that […]
August 17th, 2010 at 1:55 pm
I’ve struggled with this - using inner functions and wanting to stub them out/test them separately.
Variously, I’ve not bothered (which I dislike), injected them (which is very non-idiomatic) or more often pulled out lots of little named functions just so I can test them by themselves and then stub them out when testing the higher-level functions that use them. None of those solutions seemed good to me. Having something like you describe would be very useful - is this just thinking out loud, or something you’re going to build in to midje?
August 17th, 2010 at 1:58 pm
Oh, as a ps, the Gist embedding does a good job of syntax highlighting, but one downside is that the code doesn’t appear in your RSS feeds (e.g. when viewing your content in Google Reader etc). An alternative might be to use something like syntaxhighlighter: http://code.google.com/p/syntaxhighlighter/. This just decorates pre blocks in your post, so the raw HTML still contains the code listing, but you still get the nice coloring. And yes, it supports Clojure :-)
August 17th, 2010 at 4:21 pm
I’ve saved up the transformations I did by hand. Had I a formal roadmap for Midje, this would be on it.