Thanks for the suggestions, but unfortunately this does not work. The reason for this is that the when
macro does not conditionally include the body. deftest
actually does that, but fails to work in this case because it adds the code to meta of a test var. Both cases break on source file compilation.
After (quite) some digging I’ve arrived at two possible solutions. The root problem is something needs to be changed at either read or compile time. I know of two features that can do that; tagged literals and macros. Both rely on conditional source code inclusion.
Tagged literals
Tagged literals like #inst transform the next form in the source code. Custom tagged literals can be added to the symbol/fn map in file data_readers.clj(c) at the root classpath. So for example:
{test clojure.core/identity}
The identity function just takes the form and returns it unmodified. The source file would look something like this:
(ns foo)
(my implementation ...)
#test
(do
(require ...)
(testing "my tests"
(deftest some-test
...)))
For a production build a different data_readers.clj(c)
file could be included that configures a different function for test
, which takes an argument and wraps it in a (comment ....)
for example.
Unfortunately there is no function in clojure.core that does something like that. Which means a custom function is required, which has to be (:require ...)
in the source file.
Custom macro
A customized macro that conditionally includes the form actually seems to work:
(defmacro tests
"Include when clojure.test/*load-tests* is true"
[& body]
(if clojure.test/*load-tests*
`(do ~@body)
`(comment ~@body)))
Which when used in source code is as follows:
(ns foo)
(my implementation ...)
(tests
(require ...)
(testing "my tests"
(deftest some-test
...)))
Instead of using clojure.test/*load-tests*
a different macro variant could be used depending on alias used.
Related: tools.build
It appears to be impossible to set values (like *load-tests*
) or inject code around tools.build. This is because compile is invoked through a generated script somewhere in a tmp directory that does not take any parameters except for compiler options. It seems that this leaves conditionally including different macro or custom tagged literals implementations as the only working solution. That is unfortunate, because that means tests included with the with-test
macro can’t be filtered out.
I hope the above makes sense. I’m surprised that there are advanced techniques (I consider custom tagged literals and macros as advanced topics) required to solve this relatively simple requirement. Any thoughts or feedback on this is appreciated.