A test-fixture macro

macros
clojure

#1

I’m trying to build a macro that helps with my test fixtures. In particular, it wraps tests in database transactions. Now, doing that raw works:

(defmacro basic-transaction-fixtures
  [& forms]
  `(clojure.test/use-fixtures
     :each
     ~(fn [f]
       (mount.core/start
        #'orca.config/env
        #'orca.db.core/*db*)
       (orca.db.test-util/with-transaction [orca.db.core/*db*]
         (clojure.java.jdbc/db-set-rollback-only! orca.db.core/*db*)
                                        ;(do [email protected]) ;; This is what doesn't work
         (f)))))

With that commented-out line it seems to work, but now I want to be able to pass in forms that will be included in the fixture. For example, I want:

(tcore/basic-transaction-fixtures
 (println ">>>>I'm in the macro!") )

Ultimately I’ll have def statements in there. Anyway, uncommenting that (do [email protected]###$%[email protected]) line (I’ve tried every variation of symbols I can think of, which clearly means I don’t know what I’m doing) doesn’t work. It spits a missing ctor error, or other things. So what should I be doing to just have it do whatever I pass before it does (f)?

EDIT the error received with the println above is:


#2

No idea, but you should paste your error message so that people can help.


#3

By uncommenting that [email protected] line, attempting to run the macro gives: CompilerException java.lang.RuntimeException: Unable to resolve symbol: forms in this context. Now, this might be because [email protected] is undefined without a syntax-quote, right? But I also don’t understand why simply changing the

'(clojure.test/use-fixtures ...

to

`(clojure.test/use-fixtures ...

results in Call to clojure.core/fn did not conform to spec: In: [0 0] val: (orca.db.test-util/f) fails spec: ...

with or without that commented line. I could use some guidance.


#4

One more clarification; the above was for running without a ~(fn ...) tilda statement. The error is different WITH a backtick and WITH a ~, if I have the (do [email protected] line:

No matching ctor found for class orca.db.test_util$basic_transaction_fixtures$fn__40580

#5

I know this isn’t answering your specific question, but is there a reason you’re using a macro for this? I’ve got fixtures that start mount components and perform database operations and they’ve seemed to work fine with just the regular higher-order function interface clojure.test exposes.


#6

My overall solution came from using the # autonaming facility:

(defmacro basic-transaction-fixtures
  [& forms]
  `(clojure.test/use-fixtures
     :each
     (fn [f#]
       (mount.core/start
        #'orca.config/env
        #'orca.db.core/*db*)
       (orca.db.test-util/with-transaction [orca.db.core/*db*]
     (clojure.java.jdbc/db-set-rollback-only! orca.db.core/*db*)
     (do [email protected])
     (f#)))))

As for the question of why use a macro here, my initial answer to that was “because I’ve not done macros before and this is a great opportunity to learn.” Also, though, I thought it was the most sensible way to insert code into a db-transaction while ensuring it wouldn’t leak into long-term DB garbage. I believe that such use of macros to extend/enhance test fixtures is pretty common, but I could be wrong.