Unit Testing with Transactions

Typically in our Unit Tests, we have something like...
describe('test suite', () => {
let tx: Transaction;
beforeEach(() => {
tx = db.getConnection();
})
afterEach(() => {
tx.rollback();
})
it('test', async () => {
const result = await tx.makeSomeDbChanges();
expect(result).toBe(something);
})
describe('test suite', () => {
let tx: Transaction;
beforeEach(() => {
tx = db.getConnection();
})
afterEach(() => {
tx.rollback();
})
it('test', async () => {
const result = await tx.makeSomeDbChanges();
expect(result).toBe(something);
})
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...
describe('test suite', () => {
it('test', async () => {
const db = drizzle(conn);
db.transaction( async (tx) => {
const result = await tx.makeSomeDbChanges();
expect(result).toBe(something);
tx.rollback();
});
})
}
describe('test suite', () => {
it('test', async () => {
const db = drizzle(conn);
db.transaction( async (tx) => {
const result = await tx.makeSomeDbChanges();
expect(result).toBe(something);
tx.rollback();
});
})
}
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
MrGrygson
MrGrygson12mo ago
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.
baronnoraz
baronnorazOP12mo ago
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.
Angelelz
Angelelz12mo ago
I agree with this
baronnoraz
baronnorazOP12mo ago
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.
Angelelz
Angelelz12mo ago
You can find inspiration in drizzle-orm's own integration tests, I really like that pattern
Angelelz
Angelelz12mo ago
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
Angelelz
Angelelz12mo ago
In that test, if there is no env variable for the database string then a docker is created
Cayter
Cayter12mo ago
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
baronnoraz
baronnorazOP12mo ago
@Angelelz that link is super helpful. Thank you! I appreciate the help and insight from everyone.
MrGrygson
MrGrygson12mo ago
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.
baronnoraz
baronnorazOP12mo ago
Thank you for that link as well!!
Want results from more Discord servers?
Add your server