Drone CI Testing: Lightweight Docker-Based Test Pipelines
Drone CI is a container-native CI/CD platform that uses Docker for every step of the pipeline. Unlike CI tools that add Docker support as an afterthought, Drone was designed from the ground up around containers — each pipeline step runs in its own Docker image with complete isolation.
This makes Drone predictable and portable. The same .drone.yml that runs locally in Drone runs identically in CI. No environment drift, no "works on my machine" issues.
How Drone Works
Drone pipelines are defined in .drone.yml at the repository root. Each pipeline consists of steps, and each step runs in a specified Docker image.
The key difference from other CI tools: steps don't share a filesystem by default. Drone uses a Docker volume to mount the repository into each step's container at the same path (/drone/src). Steps share this workspace, so files written in one step are visible in the next.
kind: pipeline
type: docker
name: default
steps:
- name: install
image: node:20
commands:
- npm ci
- name: test
image: node:20
commands:
- npm testBoth steps use node:20 and can see node_modules/ because they share the workspace volume.
Basic Pipeline Structure
kind: pipeline
type: docker
name: tests
# Clone settings (optional)
clone:
depth: 1
steps:
- name: install-dependencies
image: node:20-alpine
commands:
- npm ci
- name: lint
image: node:20-alpine
commands:
- npm run lint
- name: unit-tests
image: node:20-alpine
commands:
- npm run test:unit
- name: build
image: node:20-alpine
commands:
- npm run buildSteps execute in order. If any step fails, subsequent steps are skipped (unless you configure otherwise).
Running Different Test Types
JavaScript with Jest
steps:
- name: install
image: node:20
commands:
- npm ci
- name: unit-tests
image: node:20
environment:
CI: "true"
NODE_ENV: test
commands:
- npm test -- --coverage --ciPython with pytest
kind: pipeline
type: docker
name: python-tests
steps:
- name: install
image: python:3.12-slim
commands:
- pip install --upgrade pip
- pip install -r requirements.txt
- name: pytest
image: python:3.12-slim
commands:
- pytest -v --junitxml=test-results/junit.xmlGo tests
steps:
- name: test
image: golang:1.22
commands:
- go test ./... -v -race -coverprofile=coverage.out
- go tool cover -func=coverage.out.NET tests
steps:
- name: restore
image: mcr.microsoft.com/dotnet/sdk:8.0
commands:
- dotnet restore
- name: test
image: mcr.microsoft.com/dotnet/sdk:8.0
commands:
- dotnet test --no-restore --logger "console;verbosity=detailed"Service Containers
Drone supports service containers — containers that run alongside your pipeline steps, accessible by hostname.
PostgreSQL
kind: pipeline
type: docker
name: integration-tests
services:
- name: postgres
image: postgres:15
environment:
POSTGRES_USER: test
POSTGRES_PASSWORD: testpassword
POSTGRES_DB: testdb
steps:
- name: wait-for-postgres
image: postgres:15
commands:
- until pg_isready -h postgres -U test; do sleep 1; done
- name: run-migrations
image: node:20
environment:
DATABASE_URL: postgresql://test:testpassword@postgres/testdb
commands:
- npm ci
- npm run migrate
- name: integration-tests
image: node:20
environment:
DATABASE_URL: postgresql://test:testpassword@postgres/testdb
NODE_ENV: test
commands:
- npm run test:integrationThe service postgres is accessible as hostname postgres from all steps.
Redis
services:
- name: redis
image: redis:7-alpine
commands:
- redis-server --requirepass testpassword
steps:
- name: tests
image: node:20
environment:
REDIS_URL: redis://:testpassword@redis:6379
commands:
- npm ci
- npm testMultiple services
services:
- name: postgres
image: postgres:15
environment:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: app
- name: redis
image: redis:7
- name: rabbitmq
image: rabbitmq:3-management
environment:
RABBITMQ_DEFAULT_USER: test
RABBITMQ_DEFAULT_PASS: test
steps:
- name: integration-tests
image: node:20
environment:
DATABASE_URL: postgresql://test:test@postgres/app
REDIS_URL: redis://redis:6379
AMQP_URL: amqp://test:test@rabbitmq:5672
commands:
- npm ci
- npm run test:integrationParallel Pipelines
Drone pipelines run sequentially within a single .drone.yml pipeline definition. For parallelism, define multiple pipelines:
---
kind: pipeline
type: docker
name: unit-tests
steps:
- name: test
image: node:20
commands:
- npm ci
- npm run test:unit
---
kind: pipeline
type: docker
name: integration-tests
steps:
- name: test
image: node:20
environment:
DATABASE_URL: postgresql://test:test@postgres/app
commands:
- npm ci
- npm run test:integration
services:
- name: postgres
image: postgres:15
---
kind: pipeline
type: docker
name: e2e-tests
steps:
- name: test
image: mcr.microsoft.com/playwright:v1.44.0-jammy
commands:
- npm ci
- npx playwright testMultiple pipelines in the same .drone.yml file run in parallel on separate agents.
Pipeline dependencies
If one pipeline should run after another:
---
kind: pipeline
type: docker
name: build
steps:
- name: build
image: node:20
commands:
- npm ci
- npm run build
---
kind: pipeline
type: docker
name: e2e-tests
depends_on:
- build # wait for build pipeline to succeed
steps:
- name: e2e
image: mcr.microsoft.com/playwright:v1.44.0-jammy
commands:
- npm ci
- npx playwright testEnvironment Variables and Secrets
Environment variables
steps:
- name: test
image: node:20
environment:
NODE_ENV: test
LOG_LEVEL: debug
API_BASE_URL: https://api.staging.example.com
commands:
- npm testSecrets from Drone secret store
Store secrets in Drone's secret management (configured via drone secret add):
steps:
- name: integration-tests
image: node:20
environment:
DATABASE_URL:
from_secret: database_url
API_KEY:
from_secret: api_key
commands:
- npm ci
- npm run test:integrationAdd secrets via CLI:
drone secret add \
--repository your-org/your-repo \
--name database_url \
--value "postgresql://user:pass@prod.db/app"Or manage via the Drone web UI.
Caching
Drone doesn't have a native caching layer like some CI tools, but you can achieve caching with volume mounts or plugins.
Volume caching (self-hosted Drone)
steps:
- name: install
image: node:20
volumes:
- name: npm-cache
path: /root/.npm
commands:
- npm ci --cache /root/.npm
volumes:
- name: npm-cache
host:
path: /tmp/drone-npm-cacheThis maps a host directory to the step container, persisting across builds.
Cache plugin
steps:
- name: restore-cache
image: drillster/drone-volume-cache
volumes:
- name: cache
path: /cache
settings:
restore: true
mount:
- node_modules
- name: install
image: node:20
commands:
- npm ci
- name: rebuild-cache
image: drillster/drone-volume-cache
volumes:
- name: cache
path: /cache
settings:
rebuild: true
mount:
- node_modules
volumes:
- name: cache
host:
path: /tmp/cacheBranch Filtering
Run pipelines only on specific branches or events:
kind: pipeline
type: docker
name: pr-tests
trigger:
event:
- pull_request
steps:
- name: test
image: node:20
commands:
- npm ci
- npm testkind: pipeline
type: docker
name: main-tests
trigger:
branch:
- main
event:
- push
steps:
- name: full-test-suite
image: node:20
commands:
- npm ci
- npm run test:allExcluding branches
trigger:
branch:
exclude:
- dependabot/*
- renovate/*Step Conditions
Skip individual steps based on conditions:
steps:
- name: unit-tests
image: node:20
commands:
- npm test
- name: deploy
image: node:20
when:
branch:
- main
event:
- push
commands:
- npm run deployFailure handling
Continue the pipeline even if a step fails:
steps:
- name: lint
image: node:20
failure: ignore # don't fail the pipeline if lint fails
commands:
- npm run lint
- name: test
image: node:20
commands:
- npm testDrone with Kubernetes
For Kubernetes-native Drone, use type: kubernetes instead of type: docker:
kind: pipeline
type: kubernetes
name: tests
steps:
- name: test
image: node:20
commands:
- npm ci
- npm test
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2GiEach step runs as a Kubernetes pod, enabling fine-grained resource control.
Limitations and When to Use Drone
Strengths:
- Pure Docker — every step is a container, complete isolation
- Simple configuration — fewer abstractions than Jenkins or GitLab CI
- Self-hosted and cloud-hosted options
- Lightweight resource requirements
- Good multi-pipeline parallelism
Limitations:
- No built-in test result visualization (no dashboard like TeamCity or Azure DevOps)
- Caching requires workarounds or plugins
- Less marketplace of pre-built actions compared to GitHub Actions
- Secret management is more manual
Drone is a good fit for teams that want container-native CI with simple configuration and don't need a heavy platform with built-in test analytics. It's particularly popular in environments where you want to self-host CI without the complexity of Jenkins.
Conclusion
Drone CI's container-first design means your pipeline runs exactly the same locally and in CI. No environment drift, no agent configuration surprises — just Docker images and commands.
For testing, define your pipeline steps with the right images, add service containers for databases and caches, and use parallel pipelines for faster feedback. The .drone.yml file is readable and easy to maintain, making Drone a low-overhead CI option for teams that value simplicity and container portability.