pytest-docker
pytest-docker copied to clipboard
Option to keep containers running or use manually started ones
I have a setup where spinning up the containers for tests is quite expensive. It would be nice if there was an option to either leave contains running after the first execution or to use a project started manually beforehand. That way, the expensive boot up of the containers can be avoided for subsequent tests.
Hello,
I've run into this issue in the past myself. I solved it by temporarily removing the docker_services
fixture from my tests. But that is not an elegant solution.
Do you have an idea of how this option could be implemented? What comes to mind is either some kind of environment variable or maybe looking at the names of containers running on the system.
I would prefer the first option because it would be less likely to cause strange issues.
Pytest has command line options and this is what, for instance, pytest-kind uses for this purpose. I think the easiest thing would be to switch to a predictable project name and to provide a command line switch that disables the docker-compose down
call.
https://codeberg.org/hjacobs/pytest-kind#user-content-pytest-options
https://github.com/lovelysystems/lovely-pytest-docker/blob/master/src/lovely/pytest/docker/compose.py#L219 implements this
It’s quite easy to implement a “keep alive” mode by defining/overriding a few pytest-docker
fixtures.
By adding the following code, you’ll be able to run pytest
with a new --keepalive
option that won’t stop Docker containers. In order to avoid recreating containers in the next pytest
run, this requires to have a predictable name for Dockers, which was done by overriding the docker_compose_project_name
fixture.
def pytest_addoption(parser):
"""Add custom options to pytest.
Add the --keepalive option for pytest.
"""
parser.addoption("--keepalive", "-K", action="store_true", default=False, help="Keep Docker containers alive")
@pytest.fixture(scope="session")
def keepalive(request):
"""Check if user asked to keep Docker running after the test."""
return request.config.option.keepalive
@pytest.fixture(scope="session")
def docker_compose_project_name(keepalive, docker_compose_project_name):
"""Override `docker_compose_project_name` to make sure that we have a
unique project name if user asked to keep containers alive. This way
we won’t create Docker container every time we will start pytest."""
if keepalive:
return "pytest-myproject"
return docker_compose_project_name
@pytest.fixture(scope="session")
def docker_cleanup(keepalive, docker_cleanup):
"""If user asked to keep Docker alive, make `pytest-docker` execute
the `docker-compose version` command. This way, Docker container won’t
be shut down."""
if keepalive:
return "version"
return docker_cleanup
I do this for development work. I start my local cluster manually, and manage it myself. When running automated testing, I want pytest-docker to manage the cluster.
The simplest solution was to add a flag so that pytest-docker only runs when we set --env=docker
like so:
# Add optional flags to the commandline
def pytest_addoption(parser):
parser.addoption("--env", action="store", default="default")
parser.addoption("--compose", action="store", default="v2")
# add optional marker flags
for marker, info in default_skip_markers.items():
parser.addoption(
f"--{marker}",
action="store_true",
default=False,
help=info["help"],
)
@fixture(scope="session")
def my_service(request):
if request.config.getoption("--env") == "docker":
request.getfixturevalue("my_container")
@fixture(scope="session")
def my_container(docker_ip, docker_services):
"""Ensure that HTTP service is up and responsive."""
...