Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

187
Views
Nested transactions using savepoints for tests in clojure.jdbc and postgres

In my unit tests, I have a fixture that creates a rollback transaction in order to clean up the database after my tests have run. It looks something like this:

(defn with-rollback [test-fn]
  (let [db-conn    (db/connect db/test-pg-db)]
    (jdbc/with-db-transaction [txn db-conn {:isolation :serializable}]
      (jdbc/db-set-rollback-only! txn)
      (-> (mount/only [#'db/db])
          (mount/swap {#'db/db txn})
          (mount/start))
      (test-fn)
      (mount/stop))
    (db/disconnect db-conn)))

Then in the tests I do (use-fixtures :each fixtures/with-rollback).

This works great, except in tests where I want to test that error conditions actually rolls back transactions. For example I want to test that when a request to an external service fails I don't write anything to the db.

Is there any way to get behaviour similar to nested transactions for my use case? I had an idea to override the jdbc/db-transaction* function with something that creates savepoints when a transaction is opened and rolls back to the nearest one when an exception is caught - but I could never get it to work. Appriciate any help!

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

I was struggling with this problem as well and ultimately decided to go with a workaround of having separate files for "normal" tests and transaction tests. This way it is possible to use separate fixtures.

So you would use a rollback fixture for the normal tests and a clear/truncate fixture for the transaction tests. Truncating has a bigger performance cost, hence the fixture should be used sparingly.

Here is the truncate fixture implementation. It is assumed that the used schema is public and that there are some data stored about database migrations in a schema_migrations table that should be left intact.

(defn truncate-db [tests]
  (tests)
  (jdbc/execute! db-conn
                 "DO $$ BEGIN
                    EXECUTE 'TRUNCATE TABLE '
                    || (SELECT string_agg(table_name::text, ',')
                        FROM information_schema.tables
                        WHERE table_schema = 'public'
                        AND table_type = 'BASE TABLE'
                        AND table_name != 'schema_migrations')
                    || ' CASCADE';
                  END; $$;"))
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!