Files
superset2/docs/developer_docs/testing/backend-testing.md

5.4 KiB

title, sidebar_position
title sidebar_position
Backend Testing 3

Backend Testing

🚧 Coming Soon 🚧

Complete guide for testing Superset's Python backend, APIs, and database interactions.

Topics to be covered:

  • Pytest configuration and fixtures
  • Unit testing best practices
  • Integration testing with databases
  • API endpoint testing
  • Mocking strategies and patterns
  • Testing async operations with Celery
  • Security testing guidelines
  • Performance and load testing
  • Test database setup and teardown
  • Coverage requirements

Quick Commands

# Run all backend tests
pytest

# Run specific test file
pytest tests/unit_tests/specific_test.py

# Run with coverage
pytest --cov=superset

# Run tests in parallel
pytest -n auto

# Run only unit tests
pytest tests/unit_tests/

# Run only integration tests
pytest tests/integration_tests/

Testing Alerts & Reports with Celery and MailHog

The Alerts & Reports feature relies on Celery for task scheduling and execution. To test it locally, you need Redis (message broker), Celery Beat (scheduler), a Celery Worker (executor), and an SMTP server to receive email notifications.

Prerequisites

  • Redis running on localhost:6379
  • MailHog installed (a local SMTP server with a web UI for viewing caught emails)

superset_config.py

Your CeleryConfig must include beat_schedule. When you define a custom CeleryConfig class in superset_config.py, it replaces the default entirely. If you omit beat_schedule, Celery Beat will start but never schedule any report tasks.

from celery.schedules import crontab
from superset.tasks.types import ExecutorType

REDIS_HOST = "localhost"
REDIS_PORT = "6379"

class CeleryConfig:
    broker_url = f"redis://{REDIS_HOST}:{REDIS_PORT}/0"
    result_backend = f"redis://{REDIS_HOST}:{REDIS_PORT}/0"
    broker_connection_retry_on_startup = True
    imports = (
        "superset.sql_lab",
        "superset.tasks.scheduler",
        "superset.tasks.thumbnails",
        "superset.tasks.cache",
    )
    worker_prefetch_multiplier = 10
    task_acks_late = True
    beat_schedule = {
        "reports.scheduler": {
            "task": "reports.scheduler",
            "schedule": crontab(minute="*", hour="*"),
        },
        "reports.prune_log": {
            "task": "reports.prune_log",
            "schedule": crontab(minute=0, hour=0),
        },
    }

CELERY_CONFIG = CeleryConfig

# SMTP settings pointing to MailHog
SMTP_HOST = "localhost"
SMTP_PORT = 1025
SMTP_STARTTLS = False
SMTP_SSL = False
SMTP_USER = ""
SMTP_PASSWORD = ""
SMTP_MAIL_FROM = "superset@localhost"

# Must match where your frontend is running
WEBDRIVER_BASEURL = "http://localhost:9000/"

ALERT_REPORTS_EXECUTE_AS = [ExecutorType.OWNER]

FEATURE_FLAGS = {
    "ALERT_REPORTS": True,
    # Recommended for better screenshot support (WebGL/DeckGL charts)
    "PLAYWRIGHT_REPORTS_AND_THUMBNAILS": True,
}

:::note Do not include "superset.tasks.async_queries" in CeleryConfig.imports unless you need Global Async Queries. That module accesses current_app.config at import time and will crash the worker with a "Working outside of application context" error. :::

Starting the Services

Start MailHog, then Celery Beat and Worker in separate terminals:

# Terminal 1 - MailHog (SMTP on :1025, Web UI on :8025)
MailHog

# Terminal 2 - Celery Beat (scheduler)
celery --app=superset.tasks.celery_app:app beat --loglevel=info

# Terminal 3 - Celery Worker (executor)
celery --app=superset.tasks.celery_app:app worker --concurrency=1 --loglevel=info

Use --concurrency=1 to limit resource usage on your dev machine.

Verifying the Setup

  1. Beat should log Scheduler: Sending due task reports.scheduler (reports.scheduler) once per minute
  2. Worker should log Scheduling alert <name> eta: <timestamp> for each active report
  3. Create a test report in Settings > Alerts & Reports with a * * * * * cron schedule
  4. Check http://localhost:8025 (MailHog web UI) for the email within 1-2 minutes

Troubleshooting

Problem Solution
Beat shows no output Ensure beat_schedule is defined in your CeleryConfig and --loglevel=info is set
"Report Schedule is still working, refusing to re-compute" Previous executions are stuck. Reset with: UPDATE report_schedule SET last_state = 'Not triggered' WHERE id = <id>;
Task backlog overwhelming the worker Flush Redis: redis-cli FLUSHDB, then restart Beat and Worker
Screenshot timeout Ensure your frontend dev server is running and WEBDRIVER_BASEURL matches its URL

This documentation is under active development. Check back soon for updates!