How to Run Plane’s Test Suite Using docker-compose-test.yml with pytest and Django Factories

The Plane repository provides a containerized test environment where docker-compose-test.yml orchestrates PostgreSQL, Redis, RabbitMQ, and MinIO services, then executes pytest inside an api-tests container that uses factory-boy factories to generate Django test data.

The open-source project management platform Plane (makeplane/plane) ships with a complete Docker-based testing infrastructure that eliminates local dependency conflicts. By leveraging docker-compose-test.yml, developers can run the entire Django API test suite inside isolated containers that automatically wire up the required database, cache, message queue, and object storage services. This setup ensures that tests run against a clean, reproducible environment while utilizing Django factories defined in apps/api/plane/tests/factories.py to create realistic model instances.

Understanding the Test Environment Architecture

The docker-compose-test.yml file defines a microservices stack specifically designed for testing. Unlike production configurations, this composition uses ephemeral storage and health checks to guarantee a pristine state for every test run.

Service Dependencies

The compose file provisions four infrastructure services that support the test suite:

  • test-db – Runs PostgreSQL 15 Alpine with a health-check that executes pg_isready before marking the service as healthy.
  • test-redis – Deploys Valkey (Redis-compatible) with a ping-based health verification.
  • test-mq – Provides RabbitMQ for message queue testing with connectivity health checks.
  • test-minio – Spins up a MinIO S3 server that automatically creates a bucket and remains available for file upload tests.

Each service mounts configuration from apps/api/.env (referenced at lines 31-33, 60-62, and 78-80 in the compose file) and stores data in tmpfs volumes (lines 36-38, 48-50, 67-68, and 92-94), ensuring that filesystem state is completely discarded when containers stop.

The api-tests Service Configuration

The api-tests service is the entry point for executing the test suite. As defined in docker-compose-test.yml (lines 100-119), this service:

  1. Builds from apps/api/Dockerfile.dev (lines 100-104)
  2. Injects environment variables that override production settings to point at the test containers (lines 111-119):
    • DJANGO_SETTINGS_MODULE=plane.settings.test
    • POSTGRES_HOST, REDIS_HOST, RABBITMQ_HOST, and AWS_S3_ENDPOINT_URL mapped to the service hostnames

The container’s entrypoint installs dependencies from requirements/test.txt and then invokes pytest (lines 40-47), though this command can be overridden for selective test execution.

Running the Test Suite with docker-compose-test.yml

Plane supports multiple execution patterns depending on whether you need to run the full suite or specific subsets.

Execute the Full Test Suite

To build the images, start all dependencies, and run the complete pytest suite:

docker compose -f docker-compose-test.yml up --build --abort-on-container-exit --exit-code-from api-tests

This command waits for all health checks to pass, executes pytest inside the api-tests container, and exits with the same exit code as the test runner, making it suitable for CI/CD pipelines.

Run Selective Tests

You can override the default command to execute specific test categories using pytest markers or path arguments:


# Run only unit tests (marked with @pytest.mark.unit)

docker compose -f docker-compose-test.yml run --rm --build api-tests pytest -m unit

# Run a specific test file or pattern

docker compose -f docker-compose-test.yml run --rm api-tests pytest plane/tests/unit -k "test_workspace"

The --rm flag ensures the container is removed after execution, while --build guarantees the latest code changes are included.

Clean Up the Environment

After testing, remove all containers and temporary volumes to ensure a completely fresh state for the next run:

docker compose -f docker-compose-test.yml down -v

The -v flag removes the tmpfs volumes, eliminating any residual database state or uploaded files.

Creating Test Data with Django Factories

Plane uses factory-boy factories located in apps/api/plane/tests/factories.py to instantiate Django models without manual setup. These factories handle complex relationships and hashing automatically.

Available Factory Classes

The test suite includes factories for core entities:

  • UserFactory – Generates a User instance with a unique email address and hashed password (using set_password).
  • WorkspaceFactory – Creates a Workspace and automatically assigns an owner via UserFactory.
  • WorkspaceMemberFactory and ProjectMemberFactory – Generate membership relationships using SubFactory to link users with workspaces or projects.
  • ProjectFactory – Instantiates projects with randomized attributes and proper foreign key relationships.

Factory Usage Example

Tests import these factories and invoke them to create persisted database records:

from plane.tests.factories import UserFactory, WorkspaceFactory

def test_workspace_permissions():
    user = UserFactory()
    workspace = WorkspaceFactory(owner=user)
    # Assert workspace creation logic and permissions

    assert workspace.owner == user
    assert workspace.name is not None

Because the factories reside in the repository at apps/api/plane/tests/factories.py, they are automatically available when pytest runs inside the Docker container, requiring no additional installation steps.

Configuration and Environment Setup

Before executing tests, you must generate the environment file that the compose services and Django settings share.

Environment File Preparation

Run the setup script to create apps/api/.env from the template:

./setup.sh

This file supplies database credentials, Redis host, RabbitMQ authentication, and S3 endpoint variables that both the test-db, test-redis, test-mq, and test-minio services consume, and that the api-tests service reads via Django settings.

Django Test Settings

The api-tests service sets DJANGO_SETTINGS_MODULE=plane.settings.test, which configures:

  • Database connections pointing to the test-db service
  • Redis cache configuration targeting test-redis
  • Celery broker settings for test-mq
  • S3 storage endpoint set to the test-minio service

According to the source code in apps/api/plane/settings/test.py, these settings load from the same environment variables injected by docker-compose-test.yml, ensuring consistency between the Docker services and the Django application configuration.

Summary

  • The docker-compose-test.yml file orchestrates a complete test stack including PostgreSQL, Valkey, RabbitMQ, and MinIO, with all data stored in temporary tmpfs volumes.
  • The api-tests service builds the API image from Dockerfile.dev and executes pytest against the Django codebase using test-specific settings.
  • Django factories in apps/api/plane/tests/factories.py provide factory-boy implementations for creating realistic User, Workspace, and Project instances during tests.
  • You can run the full suite with docker compose up or target specific tests using docker compose run with custom pytest arguments like -m unit or -k pattern.
  • Always use docker compose down -v after testing to remove temporary volumes and ensure clean subsequent runs.

Frequently Asked Questions

How do I run only the unit tests without integration tests?

Use the pytest marker filter when running the api-tests service: docker compose -f docker-compose-test.yml run --rm api-tests pytest -m unit. This executes only tests decorated with @pytest.mark.unit, skipping slower integration tests that require full service interaction.

Why does the test suite use Valkey instead of Redis for the test-redis service?

The test-redis service runs Valkey, which is Redis-compatible and provides the same protocol and command set required for Plane’s cache and queue backends. This choice ensures compatibility while potentially offering different performance characteristics during test execution.

Where are the database tables created during test runs?

The test-db service provisions a PostgreSQL 15 instance that Django connects to using the DATABASE_URL configured in apps/api/.env. When pytest starts, Django’s test runner creates the test database schema from migrations, and the factories populate tables with data. All data disappears when you run docker compose down -v because the service uses tmpfs storage.

Can I debug a failing test with an interactive shell?

Yes, override the default command to access a bash shell inside the test container: docker compose -f docker-compose-test.yml run --rm api-tests /bin/bash. From there, you can manually run pytest with the --pdb flag or inspect the environment variables confirmed in plane.settings.test.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →