tuanchris f6de1c6edf fix: preserve playlist state when async task is cancelled by TestClient 1 hafta önce
..
fixtures 784374d2df chore(backend-testing-01): create test directory structure 1 hafta önce
integration f6de1c6edf fix: preserve playlist state when async task is cancelled by TestClient 1 hafta önce
unit a1c2252b89 test(backend-testing-01): add playlist API endpoint tests 1 hafta önce
README.md cdb06b4dfc docs: add testing guide README 1 hafta önce
__init__.py 784374d2df chore(backend-testing-01): create test directory structure 1 hafta önce
conftest.py 6b43ca971f chore(backend-testing-01): create root conftest.py with shared fixtures 1 hafta önce

README.md

Testing Guide

This document explains how to run tests for the Dune Weaver backend.

Quick Start

# Install test dependencies
pip install -r requirements-dev.txt

# Run all unit tests (no hardware needed)
pytest tests/unit/ -v

# Run with coverage report
pytest tests/ --cov=modules --cov-report=term-missing

Test Structure

tests/
├── conftest.py              # Shared fixtures
├── unit/                    # Unit tests (run in CI, no hardware)
│   ├── conftest.py
│   ├── test_api_patterns.py
│   ├── test_api_playlists.py
│   ├── test_api_status.py
│   ├── test_connection_manager.py
│   ├── test_pattern_manager.py
│   └── test_playlist_manager.py
├── integration/             # Integration tests (require hardware)
│   ├── conftest.py
│   ├── test_hardware.py
│   ├── test_playback_controls.py
│   └── test_playlist.py
└── fixtures/                # Test data files

Unit Tests

Unit tests mock all hardware dependencies and run quickly. They're safe to run anywhere.

# Run all unit tests
pytest tests/unit/ -v

# Run specific test file
pytest tests/unit/test_pattern_manager.py -v

# Run specific test
pytest tests/unit/test_api_status.py::test_get_status -v

# Run tests matching a pattern
pytest tests/unit/ -v -k "playlist"

Integration Tests

Integration tests require the sand table hardware to be connected. They are skipped by default.

# Run integration tests (with hardware connected)
pytest tests/integration/ --run-hardware -v

# Run specific integration test file
pytest tests/integration/test_playback_controls.py --run-hardware -v

# Run with output visible (helpful for debugging)
pytest tests/integration/ --run-hardware -v -s

Integration Test Categories

File What it tests Duration
test_hardware.py Serial connection, homing, movement, pattern execution ~5-10 min
test_playback_controls.py Pause, resume, stop, skip, speed control ~5 min
test_playlist.py Playlist modes, clear patterns, state updates ~5 min

Safety Notes

  • Movement tests physically move the table — ensure the ball path is clear
  • Homing tests run the homing sequence — table will move to home position
  • Pattern tests execute real patterns — star.thr runs end-to-end

Coverage Reports

# Terminal report
pytest tests/ --cov=modules --cov-report=term-missing

# HTML report (creates htmlcov/ directory)
pytest tests/ --cov=modules --cov-report=html
open htmlcov/index.html

# XML report (for CI tools)
pytest tests/ --cov=modules --cov-report=xml

CI Behavior

When CI=true environment variable is set:

  • All @pytest.mark.hardware tests are automatically skipped
  • Unit tests run normally

    # Simulate CI environment locally
    CI=true pytest tests/ -v
    

Common Commands

Command Description
pytest tests/unit/ -v Run unit tests
pytest tests/integration/ --run-hardware -v Run integration tests
pytest tests/ --cov=modules Run with coverage
pytest tests/ -v -k "pattern" Run tests matching "pattern"
pytest tests/ -x Stop on first failure
pytest tests/ --lf Run only last failed tests
pytest tests/ -v -s Show print statements

Adding New Tests

Unit Test Example

# tests/unit/test_my_feature.py
import pytest
from unittest.mock import MagicMock, patch

def test_my_function():
    """Test description here."""
    # Arrange
    expected = "result"

    # Act
    result = my_function()

    # Assert
    assert result == expected

@pytest.mark.asyncio
async def test_async_function(async_client):
    """Test async endpoint."""
    response = await async_client.get("/my_endpoint")
    assert response.status_code == 200

Integration Test Example

# tests/integration/test_my_hardware.py
import pytest

@pytest.mark.hardware
@pytest.mark.slow
def test_hardware_operation(hardware_port, run_hardware):
    """Test that requires real hardware."""
    if not run_hardware:
        pytest.skip("Hardware tests disabled")

    from modules.connection import connection_manager

    conn = connection_manager.SerialConnection(hardware_port)
    try:
        assert conn.is_connected()
        # ... test hardware operation
    finally:
        conn.close()

Troubleshooting

Tests hang or timeout

  • Check if hardware is connected and powered on
  • Verify serial port is not in use by another application
  • Try running with -s flag to see output

Import errors

  • Ensure you're in the project root directory
  • Install dependencies: pip install -r requirements-dev.txt

Hardware tests skip unexpectedly

  • Make sure to pass --run-hardware flag
  • Check that CI environment variable is not set

Coverage shows 0%

  • Ensure relative_files = true is in pyproject.toml
  • Run from project root directory