What is the specific use case of these, relating to unit testing?
Why not just have the container execute unit tests, once that process ends and the container closes itself? This wouldn’t need anything additional.
I don’t get it, how would a database container run your unit tests? And unless you know some secret option to stop the database after, say, it is idle for a few seconds, it will continue running.
The purpose is to test database dependent code by spinning up a real database and run your code against that.
Ah! That’s what I didn’t understand. So its not a container for executing unit tests. Its a container for dependencies to support unit tests. That is not clear from the readme unless I missed something
edit - the title could be “Self terminating containers for real world dependencies to support your unit tests”
This feels more like an integration test than a unit test to me. Maybe that’s not an important distinction to make, but it feels like it would also help communicate intent.
I’m reading this scratching my head going “If your unit tests need a database they ain’t a unit test”.
Thanks man, my brain was short-circuited on Testcontainers so I couldn’t write better. Also I am stealing the title.
So it’s not for unit tests, that’s where the confusion stems
Why do your unit tests need a container at all? They’re supposed to test individual pieces of code, not the whole functioning app.
When you unit test a component that interacts with an external service you often need to mock that interaction.
I’m yet to find a developer who likes to write mocks; on top of that they might create flaky tests because the interaction is not authentic.
With testcontainers you don’t need to mock them.
Edit: integration tests might be included in the process, but not necessarily. If your module interacts with e.g. Redis, you’re still only testing your module in isolation. Redis is just an external dependency.
this is a semantic argument that i don’t want to put too much weight into, but i tend to agree that if you need a database instance or an intricate mock you’re not really doing unit testing. what we’re talking about at that point is something closer on the spectrum to an integration test or else the function needs a better scope for its inputs. i mean, “a component that interacts with an external service” has a word defined for it: integration.
Yes, it’s semantics and often an unproductive argument.
Hence the reason I avoid these names on a daily basis and - in this context - would simply refer to them as “tests”.
Integration refers to “a component that interacting with another component within your project.” "a component that interacts with an external service” just means it is using a dependency, testing it ts still unit testing. And you should not mock third party dependencies.
right it’s a semantic argument and all this stuff is made up, but i’m specifically irked by some testing strategies that i’ve come across personally. big mocks and external dependencies are setup to test something simple in the business logic. it’s not always necessary to setup all that infrastructure to prove the correctness of a unit of code; that part should be abstracted away because it’s not necessarily relevant to the logic under test. the way the data is accessed, the authentication mechanisms, the overall schema—the integration points, if you will—are not necessary for unit testing. i would prefer, instead of broadening the meaning of what a unit test is, to scope the code into smaller more testable units that end up giving a better, more flexible design in the long run.
all that said, i really like this project and use something similar for testing, regardless of what kind of testing you want to call it.
Not only that, but the definition of what is external is relative; I mentioned Redis as an external dependency, but it might be considered part of your service if the module you’re testing is the only producer and consumer of that component.
Similarly, you might have a caching abstraction in the middle that is written and maintained by you/your team. Or any arbitrary number of abstractions that slowly creep outwards your service/module.
This unit vs integration naming / dispute is not helpful at all.
As the boundary between unit tests and integration tests has never be been smaller. And mocks still suck. And container first development leads to easier container deployments. And containers offer a very easy development environment setup. And containers are immutable, or at least reproducable, meaning future compatibility is much more dependable. Ever tried to run php5 unit tests any more?
Ohhhhh nononono, I am NOT besmirching containers.
I am merely pointing out that unit tests come before any deployment what so ever. If you’re having mock issues, you are writing your code wrong. Even basic OOP and encapsulation practices should keep your various classes/objects from becoming too intertwined to easily mock.
PHP? Oh… oh that explains a lot… You sweet, sweet summer child.
Yeah, testing in containers I think docker compose could do with some more support personally. Not sure what, but they have deploy and build blocks, I’d like to see a testing block and a
docker compose test
cool, we need more tooling around rootless docker / podman