[HN Gopher] Using short lived Postgres servers for testing
       ___________________________________________________________________
        
       Using short lived Postgres servers for testing
        
       Author : thunderbong
       Score  : 32 points
       Date   : 2024-06-27 18:25 UTC (4 hours ago)
        
 (HTM) web link (kaveland.no)
 (TXT) w3m dump (kaveland.no)
        
       | ludamn wrote:
       | For those interested in a easier way to set up databases, and
       | maybe other containerized services, for testing I recommend using
       | TestContainers[1], there's integrations for well known languages
       | like Go, Java, Node.js and the set up is easier than what is
       | described in the article (at least if you're already developing
       | on a container-ready workspace)
       | 
       | [1]: https://testcontainers.com/
        
       | whalesalad wrote:
       | Echoing the other comment here, https://testcontainers.com/ is a
       | great tool for this. (Or just vanilla docker in general)
       | 
       | In our core makefile we have `make pytest` to run standalone unit
       | tests, and then `make pytest_db` to run full database tests using
       | a docker container. The test suite fires up a completely fresh
       | DB, runs migrations against it, and then the test suite proceeds
       | as usual. On a per-module basis a simple fixture is used to
       | determine if the db should get reset for each test, each file, or
       | the entire module.
       | 
       | Works great on Github actions, too.
       | 
       | When the test is done, the container and all noise is
       | automatically cleaned up. No state left behind.
        
         | canadiantim wrote:
         | Seems like a great setup, thanks for sharing.
        
         | pletnes wrote:
         | Do you populate with test data, and if so, how?
        
           | vhodges wrote:
           | Yes, when the container is started you get the db url connect
           | string, you connect to it, load the schema and any test
           | data/seeds.
           | 
           | For me I just run the ddl (sitting in a .sql file) and run my
           | tests. They run with an empty db but I could have sample data
           | too the same way.
        
         | DasIch wrote:
         | > On a per-module basis a simple fixture is used to determine
         | if the db should get reset for each test, each file, or the
         | entire module.
         | 
         | That sounds interesting. How do you determine, if the db should
         | get reset?
        
           | whalesalad wrote:
           | At this time we basically reset the db after each module run,
           | but there is some flexibility.
           | 
           | Inside a test module, the developer has the ability to dicate
           | whether the entire module should share the same db state, or
           | if each individual test should get clean slate.
           | 
           | Here is an example of our `test/db/conftest.py` file that is
           | auto-loaded when the specific db test dir is invoked. This
           | essentially bootstraps everything: https://gist.github.com/wh
           | alesalad/6ecd284460ac3836a6c2b9ca8...
           | 
           | The main fixture is `database` which is set to autouse at the
           | session level. This produces one db for the entire test
           | session. This could easily be augmented to be scoped to the
           | module or even function level.
           | 
           | You will see `truncate_db` which is currently set to autouse
           | at the module level, so the tables are truncated after each
           | module is finished. This can be totally customized for your
           | own purposes.
           | 
           | I combined a few files to produce this example, but I still
           | think it is pretty concise. We are using PostgreSQL 15.x at
           | this time. Our migrations are perhaps unconventional - we
           | just have a directory in the root called `migrations/` with
           | files like 001_foo.sql, 002_bar.sql ... and we manually run
           | them on deploys. So those same migrations get run
           | sequentially all at once on boot.
           | 
           | The part here that would need to be modified for others are
           | the `service.db` monkeypatching parts. That is our core DB
           | module that everything else utilizes for grabbing a psycopg2
           | conn from the pool. The test monkeypatches these methods so
           | that the rest of the codebase 'just works' and is handed this
           | conn from the test container versus the traditional one.
        
         | JBorrow wrote:
         | Yes, I use this kind of setup in a number of places. I am also
         | a fan of running the full test suite using SQLite (if you are
         | using a compatible ORM) to make sure where you are (or not)
         | running into DB-specific behavior.
        
           | esafak wrote:
           | With testcontainers you can use exactly the same database you
           | do in production.
        
             | pvorb wrote:
             | If your application only uses one database in production,
             | you probably don't want to use an ORM, because that might
             | prevent you from using all of your db's features.
        
       | boustrophedon wrote:
       | Related self-promotion: I built pgtemp
       | (https://github.com/boustrophedon/pgtemp) to automate doing
       | exactly these mkdir/initdb/load/destroy steps.
        
         | rkaveland wrote:
         | Author of the blog post here -- that looks like exactly what I
         | needed, so I'm probably going to add a dependency to it to
         | https://github.com/kaaveland/eugene/ so I can delete a ton of
         | code. :-)
         | 
         | That looks fantastic, so I'm actually just going to put a link
         | to it in the post so that more people see it.
        
         | switchbak wrote:
         | There's a similar JVM version here:
         | https://github.com/zonkyio/embedded-postgres
         | 
         | It's well maintained and seems to do what it says on the tin. I
         | start it up once across all the suites (managing DB state as
         | required in the suite) and the overhead is very minimal.
        
       | esafak wrote:
       | I'd eventually like to use dagger.io so I can use the same
       | technology in testing, CI, and CD, but it is not mature enough
       | yet, so I'm using testcontainers for the testing part, with
       | success.
        
       | sakras wrote:
       | Disclaimer: I work at Neon
       | 
       | Neon makes this very ergonomic in a cloud setting (actually it
       | works somewhat similarly to how the article does it). You can
       | create a copy-on-write version of your prod database (a branch)
       | and use it for testing. There's also some automation we've built
       | up for doing it from GitHub CI:
       | https://neon.tech/docs/guides/neon-github-app
        
         | horse666 wrote:
         | I'd not heard of Neon, it looks interesting.
         | 
         | When you say "a copy-on-write version of your prod database",
         | from reading the docs, this includes both schema and data?
         | 
         | I couldn't find anything on data anonymisation/obfuscation -
         | how do you handle that?
        
       | twh270 wrote:
       | If you work in the JVM ecosystem, I can recommend (Java/Kotlin) +
       | Quarkus + JDBI with Postgres. Quarkus supports testcontainers out
       | of the box for tests, and it just plain works.
       | 
       | I don't have experience with it, but some people also recommend
       | jooq.
        
         | esafak wrote:
         | I use jooq with testcontainers in Kotlin just fine.
        
       | suralind wrote:
       | I started to use testcontainers for it, however my biggest
       | problem is that each test needs to start its own container which
       | is slow (right now I have about 20 test cases in my PoC).
       | 
       | testcontainers allows to stop and start containers and to reset
       | their state to a snapshot, but Go implementation seems to have a
       | bug which I reported recently [1]. It's going to be huge when
       | they fix it, as it will make tests much faster.
       | 
       | [1]: https://github.com/testcontainers/testcontainers-
       | go/issues/2...
        
       ___________________________________________________________________
       (page generated 2024-06-27 23:01 UTC)