-
Notifications
You must be signed in to change notification settings - Fork 0
Private functions
One Clojure idiom for reaching functions that have been declared private is to call them via their var, rather than via an interned symbol:
(scratch.core/super-secret-function 5) ; doesn't work
(#'scratch.core/super-secret-function 5) ; works
That works fine inside facts:
(fact
(#'scratch.core/super-secret-function 1) => 6)
You can also use vars in prerequisites:
(fact
(counter 4) => 8
(provided
(#'scratch.core/super-secret-function 4) => 4))
Calling private functions through vars looks ugly, so there's a utility function to make them available in the test namespace:
(use '[midje.util :only [testable-privates]])
(testable-privates scratch.core super-secret-function)
(fact (super-secret-function 4) => 4)
Notice that testable-privates
isn't part of Midje's default interface.
Such testable privates can't be used in prerequisites. testable-privates
creates a new var, so in the above program, there are two vars pointing at the super-secret function:
#'scratch.core/super-secret-function
#'scratch.core-tests/super-secret-function ;; Created by testable-privates
Prerequisites work by temporarily pointing vars at new functions. Therefore, in this code:
(fact
(counter 4) => 8
(provided
(super-secret-function 4) => 4))
... the prerequisite overrides the test namespace's var (#'scratch.core-tests/super-secret-function
) while leaving the original var pointing to the original function. Since the code for counter
is in the source namespace, its call to super-secret-function
uses the un-overridden var (#'scratch.core/super-secret-function
).
Consider that tests---while being clients of the code under test---are a special kind of client, one that can more reasonably be expected to have some (if not total) knowledge of a namespace's internals. We can formalize that distinction by declaring that an otherwise-private function should be available to tests. That's done with metadata:
(defn- ^{:testable true}
not-so-secret-function [n] ...)
Then, within the test namespace, all such "testables" can be interned:
(use '[midje.util :only [expose-testables]])
(expose-testables scratch.core2)
(fact (not-so-secret-function 4) => 4)
As with testable-privates
, the vars created by expose-testables
can't be used in prerequisites.