Docker helped me to significantly increase unit test speed on one project. Each test was recreating database, run dozens of DDL scripts over and over (to ensure clean environment). I reimplemented in in a way that DDL scripts were run once, then container with database was commited to an image and that image was re-used for every test. Also multiple containers were run at once, so tests could be run simultaneously. Docker is a miracle technology sometimes.
That's not normal, because the test is now not testing the code in its eventual context (which is : the transaction commits). In my experience unfortunately this is a very common pattern (tests are far removed from "reality").
Only if your database lacks the tools to do it effectively. "The transaction commits" isn't exclusive with "and you can roll back to before it started".
Would it be possible to cp /var/lib/your-database /var/lib/your-database-clean after it's been set up, then after each test just overwrite /var/lib/your-database again? I'm sure that the database will need to be properly shut down and restarted, but that is far less expensive than rebuilding a large database each time.
Disk is cheap. CPU and memory are the expensive assets.
> 3. Does not allow running multiple test simultaneously.
It does with almost every form of transaction isolation mode. Read uncommitted in Postgres still behaves as read committed, so in Postgres you're never missing the mark here.
> 1. That wouldn't work if code under test uses multiple transactions.
A lot of abstractions interpret nested transactions as save points for this reason.
It's not the only valid pattern, but it is a consistently behaving one that's straightforward to implement and gets you most of the UX you want from integration test design.
I still think that tests would be flaky without complete isolation in a different database instances. Transaction isolation is nice, but for serial isolation you would get errors when you can't commit that transaction and you'll need to repeat the test (which might cause further issues) and for lesser isolation levels you would get some phantom reads which might manifest as a rare test failures which is a terrible thing, because you can't reproduce it.