Unit Testing with Transactions
Typically in our Unit Tests, we have something like...
Does Drizzle have a mechanism for getting access to the transaction without the anonymous function route? I'd prefer not to do the following in every test...
Especially when I have to throw in error handling because
tx.rollback()
throws an Error and doesn't simply rollback.
What are others doing for unit testing?11 Replies
Do unit tests as they should be, so mock any external calls from tested function (including calls for DB)
For integration test and running it against DB, I'm just starting with fresh DB every time I launch the test, and try to have unique context in each test, so there is no need for rollback.
sorry - I should have said integration test. I was looking at using something like
jest-testcontainers
to spin up a db instance in docker, then reset the db every time. We've just used this pattern a lot on other projects. It makes it a harder sell to use Drizzle ORM. Being able to access the transaction would be helpful in other was too, given how we have used Transaction Management in our service layer.
Maybe it just feels wrong to not be able to access the transaction, especially when I've been in a world where we use save points and XA transactions.
Simply seeing how others have approached the problem is extremely helpful.I agree with this
We've only done this approach using in memory databases. I'd like to test against our MySQL or PostgreSQL databases directly. How do you go about standing up a db instance each time? I guess, how are you handling the "starting with a fresh DB every time". I'd love to see how others do this.
You can find inspiration in drizzle-orm's own integration tests, I really like that pattern
Here is MySQL for example https://github.com/drizzle-team/drizzle-orm/blob/main/integration-tests%2Ftests%2Fmysql.test.ts
GitHub
drizzle-orm/integration-tests/tests/mysql.test.ts at main · drizzle...
Headless TypeScript ORM with a head. Runs on Node, Bun and Deno. Lives on the Edge and yes, it's a JavaScript ORM too 😅 - drizzle-team/drizzle-orm
In that test, if there is no env variable for the database string then a docker is created
if u r using postgres, check out db template
In global setup, have a db template setup with ur latest schema with empty data ONCE
in beforeEach, u run a script that:
- clones this db template to a testdb<random_id> which will be used by every single unit test in isolation
- mock ur db instance to use the testdb<random_id>
The above will ensure that ur unit tests are all using different db (fully isolated) which u can even turn on test.concurrent to further speed up
Using postgres db template to clone a fresh new db is way faster than dropping/recreating/migrating db over and over again, it's about 300ms Vs 1500ms on my Mac m1
i tried testcontainer, but as we have more tests running, we ended up start limiting the concurrent tests being run, this limit is way lower than the limit using postgres db template, well, it's a matter of N containers vs N databases in 1 container with each PG container using up 165MB
@Angelelz that link is super helpful. Thank you! I appreciate the help and insight from everyone.
Or you can also use
mysql-test
package, so your test code is clean (it also runs mysql server in docker). You just need to use different env values to connect to test db and run migration to create tables. https://www.atdatabases.org/docs/mysql-test@databases
MySQL Testing with Node.js
The @databases/mysql-test library uses docker to allow you to run tests against a real MySQL database.
Thank you for that link as well!!