Container in container integration testing pattern

Does anybody else use a pattern like this?

I have one parent container which runs all of the testing code. The tests orchestrate the other containers inside it. Each test starts and stops all the required services every time.

So, for example - the test running in the test container runs “compose up” - which runs the playwright server, the app service I’m testing, the database server, etc. It would seed the database with fixtures and connect to the playwright service in set up and then begin.

It would then use the playwright service to load the website, click, etc.

Afterwards the test runs compose down and the next test is run.

The advantages:

  • It minimizes the “works on my machine” problems.
  • Cross platform - this can run the same end to end tests on windows, linux, mac and on CI or desktop without really changing anything.
  • Doesn’t make a mess on the system you run it on - all the dependencies for the tests and the app are kept in one container and volume which can be set up with one script.
  • I can do TDD with these tests.
  • They can be parallelized easily - unlike end to end tests running against a staging server.
  • The application is kept completely isolated from the testing code. No testing tools need to be installed inside the container that you will also want to deploy to prod.

I figure that most projects probably still need some tests running against a staging server to catch infrastructure-related bugs, but a lot of tests running against deployed servers could be shift lefted into a hermetically sealed end to end test like this.

This kind of pattern might have a name. If it does I don’t know what it is.

4 Likes

So I’m not sure if there is a name for it or if I am on the same idea as what you described.

I use TestContainers https://www.testcontainers.org/ for testing. When my automation runs on a service it will turn on a blank SQL Database(or a pre-created image), then use Entity Framework or RedGate Sql Automation (depends on the service) to apply the migration scripts to that container so now my database is populated and mimics prod. I then built a SQL injector to inject my specific test data at run time so I can be in total control of my inputs and outputs which helps make it easier to find errors → This actually turns on 2 containers 1 being TestContainers itself which does all the managing and clean up, the other being the SQL Database I’m ‘faking’.

I also use WireMock to mock all external dependencies, https://wiremock.org/ , that way my system is totally isolated. So tests runs it write to a container that mimics my prod database, all my api calls are now mocked so I’m not writing to any other database.

I’ve used this on containerized apps and non-containerized apps.

Interesting! I’d not heard of testcontainers before.

Yep that’s almost identical to what I described - especially including the use of wiremock to ensure everything is 100% sealed from the outside world. What do you call this type of set up?