is there a best practice for database testing, e.g mocks for clojure.java.jdbc?
when I want to mock something in clojure that has side effects, like database access or network io, I normally create a protocol for that, and then have a test and production implementation. Not sure if this is the best way to do it.
That's a reasonable way to do it, unless the surface area of the API you're using is big enough that becomes a pain.
An alternative is isolating your DB-accessing code from you business logic and testing the business logic separately -- more pure FP. Can be hard if you have a lot of DB access.
Or just use a test DB connection and setup/teardown test data around your tests. That's what we do for a lot of our data-intensive functions/tests.
I do the protocol thing as well, using a sort-of repository pattern defining specific queries and mutations against the database as well (or a part thereof).
for tests of the surrounding business logic, I can then mock the db with an in-memory store, and then the actual implementation that talks to the database has its own focused tests.
One important issue to bear in mind is that if you're trying to test actual SQL queries, you need to test it against a real database and it needs to be the one (you're planning to use) in production -- since the lightweight / in-memory / local file databases don't support the same SQL operations as the Big Ones do.
@albaker So it really depends on exactly what you're trying to test.
I was thinking more like a lein profile w/ a testdb that gets spun up each time, or something along those lines
if you use protocols, you can have a testdb settings in your test that uses the testdb
the db name, host ,etc could be changed when that Database is initialized. I normally use a component for that
then all my queries in test use that component
in dev they use a different one, and in prod the production-ready one
you can externalize those settings too
Yeah, we have a Database Component (Stuart Sierra) and initialize it differently in dev/qa/prod (from external config files), then we have a dev-only script that tears down and builds a test DB (with a bunch of essentially random-but-conforming data). We use Boot so it's easy to write new build tasks (as Clojure functions) -- we have a lot of machinery in our build.boot
file, including DB migrations (schema changes), data migrations (data changes), etc.
I find tests run quite fast against a db if I run them in a transaction and roll the transaction back — you can run your migration once at the start of the test suite and then run everything else on top of that