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

> Learn to run Plane's test suite using docker-compose-test.yml. This guide explains how pytest and Django factories orchestrate PostgreSQL, Redis, RabbitMQ, and MinIO for seamless testing.

- Repository: [Plane/plane](https://github.com/makeplane/plane)
- Tags: how-to-guide
- Published: 2026-06-22

---

**The Plane repository provides a containerized test environment where [`docker-compose-test.yml`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/apps/api/plane/tests/factories.py) to create realistic model instances.

## Understanding the Test Environment Architecture

The [`docker-compose-test.yml`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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:

```bash
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:

```bash

# 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:

```bash
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`](https://github.com/makeplane/plane/blob/main/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:

```python
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`](https://github.com/makeplane/plane/blob/main/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:

```bash
./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`](https://github.com/makeplane/plane/blob/main/apps/api/plane/settings/test.py), these settings load from the same environment variables injected by [`docker-compose-test.yml`](https://github.com/makeplane/plane/blob/main/docker-compose-test.yml), ensuring consistency between the Docker services and the Django application configuration.

## Summary

- The **[`docker-compose-test.yml`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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`.