[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)