Live data from Hacker News

Setting up PostgreSQL for running integration tests

gajus.com

31–40 of 50 posts

Re: Setting up PostgreSQL for running integration tests

#31

Why can't you just create a pool of databases and truncate all tables after each run ? That should be pretty fast

DELETE is faster on a small amount of data.

But yea, DELETEing is faster than creating a DB from template (depends on how much you have to delete, of course). However, templates allow parallelism by giving its test its own database. I ended up doing a mix of both: create a DB if there's not one available, or reuse one if available, always tearing down data.

Re: Setting up PostgreSQL for running integration tests

#32
post #7

Earlier quoted context omitted.

Testcontainers are anything but fast in my experience. With the image pre-pulled, the most basic mysql testcontainer takes about 5 seconds from calling RunContainer to it being ready to go.

I use TestContainers in my Java Spring Boot application coupled with Liquibase. I have it set up so that the PG instance is created once with Liquibase initializing it from vanilla PG to a fully created empty application database, then all the integration tests reuse the same by overriding the stop() method to an empty one. Running the full suite of tests is about 5-10 mins on a relatively low-powered build server, w…

You're describing a pretty different testing strategy, where you only use one database and ensure isolation through transactions. It's a good strategy for your use-case, but it's not what the article talks about (they do mention this transactional approach and why it doesn't work for them)

Re: Setting up PostgreSQL for running integration tests

#33

There's one idea I'm not sure being described. Basically you create docker container from some postgres image. Then you run DDL scripts. Then you stop this container and commit it as a new image. And now you can create new container from this new image and use it for test. You can even parallelize tests by launching multiple containers. It should be fast enough thanks to docker overlay magic. And it should work with…

I would think the fundamental issue with this is similar to what the author described with template databases: > However, on its own, template databases are not fast enough for our use case. The time it takes to create a new database from a template database is still too high for running thousands of tests: And then in the timing shows that this took about 2 seconds. Launching another container is surely going to be…

Starting each test with a totally clean template ensures consistent reproducibility, I’ll give you that, but it also isn’t real world, either. You only have the data that the test seeds which favors tests (and by extension business logic) written only with the “happy path” in mind. I think the smell for when tests are stepping on each other causing flakey runs, is that the logic being tested isn’t written for non-happy paths, or, the tests are asserting entirely too specific datasets or outcomes and anything else results in a failure. In the real world, other systems may very well be touching the same data or tables that your code is interacting with, so it being able to handle that kind of situation will produce a more fault tolerant system overall, which will serve to deliver value even if other systems go haywire and produce unexpected data you are looking at. Of course the need to handle that extra complexity is going to vary depending on business needs or other determining factors.

Re: Setting up PostgreSQL for running integration tests

#34

There's one idea I'm not sure being described. Basically you create docker container from some postgres image. Then you run DDL scripts. Then you stop this container and commit it as a new image. And now you can create new container from this new image and use it for test. You can even parallelize tests by launching multiple containers. It should be fast enough thanks to docker overlay magic. And it should work with…

I would think the fundamental issue with this is similar to what the author described with template databases: > However, on its own, template databases are not fast enough for our use case. The time it takes to create a new database from a template database is still too high for running thousands of tests: And then in the timing shows that this took about 2 seconds. Launching another container is surely going to be…

[deleted]

Re: Setting up PostgreSQL for running integration tests

#35
> The other limitation of template databases to be aware of is that no other sessions can be connected to the source database while it is being copied. CREATE DATABASE will fail if any other connection exists when it starts; during the copy operation, new connections to the source database are prevented. It is an easy enough limitation to work around using a mutex pattern, but it is something to be aware of.

    -- Prevent new connections to template db
    update pg_database
    set datallowconn = false
    where datname = 'my_template_db';

    -- Close all current connections
    select pg_terminate_backend(procpid)
    from pg_stat_activity
    where datname = 'my_template_db';

Re: Setting up PostgreSQL for running integration tests

#36

There's one idea I'm not sure being described. Basically you create docker container from some postgres image. Then you run DDL scripts. Then you stop this container and commit it as a new image. And now you can create new container from this new image and use it for test. You can even parallelize tests by launching multiple containers. It should be fast enough thanks to docker overlay magic. And it should work with…

I think the idea is to get a clean DB for every test in your suite.

Your solution requires spinning up hundreds of docker images per test run..

We do the same thing as described with MS SQL; takes about 1 sec to get a fresh DB that way.

While MS SQL takes 30 seconds or something from Docker image.

Re: Setting up PostgreSQL for running integration tests

#37
post #7

Earlier quoted context omitted.

Testcontainers are anything but fast in my experience. With the image pre-pulled, the most basic mysql testcontainer takes about 5 seconds from calling RunContainer to it being ready to go.

I use TestContainers in my Java Spring Boot application coupled with Liquibase. I have it set up so that the PG instance is created once with Liquibase initializing it from vanilla PG to a fully created empty application database, then all the integration tests reuse the same by overriding the stop() method to an empty one. Running the full suite of tests is about 5-10 mins on a relatively low-powered build server, w…

The article is discussing the usecase where each test/set of assertions as a clean DB. I.e. hundreds of DBs per test run.

Are you talking about a single DB reused for each test? That is of course no problem...

Our suite spends 3 to 10 minutes to run too. It provisions about a hundred databases (takes 1 sec each DB template clone.. the wall clock is running stuff in parallell)

Also, every time we change code and run a related test locally we make a new DB to run its test. If that took more than 1 second I would go crazy.

Re: Setting up PostgreSQL for running integration tests

#38
We do the same thing with Microsoft SQL.

Each time the hash of our migrations change, we make a new template DB. That takes about 30 seconds to run all our migrations..

If the hash didn't change, clone the template of the given hash. This takes less than 1 second.

Some advantages not mentioned in article:

- When developing locally, a new DB clone is made to run my single test interactively. If this took much more than a second I would get rather annoyed.

- Yes a test suite can share a DB for full suite if all tests are written without hardcoding anything and provisiom new IDs always etc. But it is super useful to run a function QueryDump("select * from MyTable") in the test of the code I am working on and the full table dump only having what that single test worked on during debugging, speeds up debugging a lot vs querying for whatever random ID my test allocated.

Re: Setting up PostgreSQL for running integration tests

#39

Why can't you just create a pool of databases and truncate all tables after each run ? That should be pretty fast

DELETE is faster on a small amount of data. But yea, DELETEing is faster than creating a DB from template (depends on how much you have to delete, of course). However, templates allow parallelism by giving its test its own database. I ended up doing a mix of both: create a DB if there's not one available, or reuse one if available, always tearing down data.

TRUNCATE is faster than DELETE. You could have 100 dbs, each test first acquires one, runs, truncates, releases. No need to create more dbs on the fly.

Re: Setting up PostgreSQL for running integration tests

#40
We just copy a schema run test on a copy, and drop it afterwards.

It can run in parallel if you name schemas randomly, or by test name.

You only need one DB, no need to even re-connect, start DB cluster or whatever. It can all work with a single persistent connection.

And it's much less resource intensive.

Post reply on HN