Meet KloudKIT TestShed, a tidy home for your integration-testing power tools.
It snap-fits into
pytest, auto-provisions Docker, runs Playwright, and cleans up after itself so you can focus on building sharp tests.
- Automated Docker management: Spin up and control containers from tests.
- Playwright integration: Run browser tests in isolated Docker environments.
- Configurable via markers & CLI: Tune environments per test or suite.
- Automatic resource cleanup: Ensures a clean state after tests.
pip install testshedTestShed fixtures are automatically available when --shed is enabled.
pytest --shedFor manual control or when --shed is not used, you can still import specific fixtures:
from kloudkit.testshed.fixtures.docker import docker_sidecar
from kloudkit.testshed.fixtures.shed import shed
from kloudkit.testshed.fixtures.playwright import playwright_browserTestShed provides fixtures to manage containers inside your tests.
Use the shed fixture for smart container management with configurable defaults:
import pytest
from kloudkit.testshed.docker import Container, HttpProbe
class MyAppContainer(Container):
DEFAULT_USER = "app"
@pytest.fixture(scope="session")
def shed_container_defaults():
"""Override this fixture to set project-specific defaults."""
return {
"container_class": MyAppContainer,
"envs": {"APP_PORT": 3000},
"probe": HttpProbe(port=3000, endpoint="/health"),
}
def test_my_app(shed):
# Uses your configured defaults automatically
assert shed.execute("whoami") == "app"
@shed_env(DEBUG="true")
def test_my_app_with_debug(shed):
# New container with override, merged with defaults
assert shed.execute("echo $DEBUG") == "true"
assert shed.execute("echo $APP_PORT") == "3000"You can also use the factory directly:
def test_custom_setup(shed_factory):
container = shed_factory(envs={"CUSTOM_VAR": "value"})
# ... test logic ...For a lower-level API, use the docker_sidecar fixture to create containers:
import pytest
def test_my_docker_app(docker_sidecar):
# Launch a simple Nginx container
nginx = docker_sidecar("nginx:latest", publish=[(8080, 80)])
# Execute a command inside the container
assert "nginx version" in nginx.execute(["nginx", "-v"])
# Access the container's IP
print(f"Nginx container IP: {nginx.ip()}")
# Interact with the file system
assert "/usr/share/nginx/html" in nginx.fs.ls("/usr/share/nginx")Configure containers using pytest markers/decorators:
@shed_config(**kwargs): Generic container args.@shed_env(**envs): Environment variables.@shed_volumes(*mounts): Volume mounts as(source, dest)orBaseVolume.@shed_mutable(): Force non-default shed for tests that perform mutable operations.
from kloudkit.testshed.docker import InlineVolume, RemoteVolume
@shed_env(MY_ENV_VAR="hello")
@shed_volumes(
("/path/to/host/data", "/app/data"),
InlineVolume("/app/config.txt", "any content you want", mode=0o644),
RemoteVolume("/app/remote-config.json", "https://api.example.com/config.json", mode=0o644),
)
def test_configured_docker_app(shed):
# ... test logic ...Get a Playwright browser instance running in Docker via playwright_browser:
def test_example_website(playwright_browser):
page = playwright_browser.new_page()
page.goto("http://example.com")
assert "Example Domain" in page.title()
# ... more Playwright test logic ...TestShed extends pytest with options to control the Docker environment:
--shed: Enable TestShed for the current test suite (default: disabled).--shed-image IMAGE: Base image (e.g.,ghcr.io/acme/app).--shed-tag TAG|SHA: Image tag or digest (default:tests).--shed-build-context DIR: Docker build context (default:pytest.inidirectory).--shed-image-policy POLICY: Image acquisition policy for building or pulling (default:pull).--shed-skip-bootstrap: Skip Docker bootstrapping (useful for unit tests).
Note
When TestShed is installed globally, you must explicitly enable it per suite with
--shed.
This prevents it from configuring Docker in projects that don't use it.
The --shed-image-policy option controls how TestShed acquires Docker images:
pull(default): Pull image if not found locally, build as fallback.build: Build only if image doesn't exist locally.require: Require existing local image (fails if not found).rebuild: Always rebuild the image.
# Enable TestShed for your suite
pytest --shed --shed-image my-test-image --shed-image-policy rebuild
# Run tests without TestShed (default)
pytest