Fork me on GitHub
#testing
<
2022-10-10
>
zeddan11:10:04

Does anyone have experience with using transactions with jdbc in a fixture? I’d love to see an example of how it could look like in a real project

zeddan13:10:29

I have this snippet:

(defn db-transaction [test]
  (with-redefs [cnf/order (fn [] {:jdbcUrl db-url})]
    (db/start!)
    (jdbc/with-transaction [t (db/order-conn) {:rollback-only true}]
                           (test))))
In a test, I’m creating a record in the database (not using a transaction), but it seems that the record is persisted even after the transaction. Is this because I’m not using t somewhere in the fixture? If so, how can I make it so that the (test) function creates the record inside a transaction?

seancorfield15:10:33

You could use a dynamic Var and have binding inside with-transaction -- but you'll also have to be careful not to have any transactions in the code you're testing since transactions do not nest by default. There are ways to have those nested transaction act as no-ops (the default behavior on c.j.j) but unless you're very careful, you're going to get different behavior in tests than in production code if you start doing that because the scope of the transaction will change (from the localized place where you might expect rollback on an exception, to the global place within the test).

seancorfield15:10:01

Overall, I don't find using transactions in test fixtures to work very well -- and instead we ensure that tests a) set up the specific DB context/data they need and b) restore the DB context/data explicitly at the end. That's a lot more complicated "in the small" but it's also a lot more explicit and a lot safer. We have written some test macros that wrap tests and can read specified data, set up test data, run the test, then tear down the test data and restore the other specified data, to make it less error prone. Another option is to use a throwaway test database for each group of tests, preferably an in-memory one as long as the SQL you use is compatible with both. For PostgreSQL, I recommend the Embedded PostgreSQL library (see the next.jdbc tests for how to use that).

zeddan11:10:23

Thank you for your insights!

plexus07:10:45

Woah didn't know there was such a thing as an embedded postgres. That's really good to know.