mirror of
https://github.com/aserper/masto-rss.git
synced 2025-12-15 04:25:24 +00:00
6.1 KiB
6.1 KiB
Testing Guide for Masto-RSS
This document describes the testing strategy and how to run tests for the Masto-RSS bot.
Test Architecture
The test suite is organized into two main categories:
Unit Tests (test_bot.py)
- Test individual functions and methods in isolation
- Use mocks and stubs for external dependencies
- Fast execution time
- High code coverage
- Test edge cases and error handling
Integration Tests (test_integration.py)
- Test interactions between components
- Mock external services (RSS feeds, Mastodon API)
- Test end-to-end workflows
- Verify data persistence
- Test error recovery
Running Tests Locally
Prerequisites
# Install test dependencies
# Install dependencies
uv sync --all-extras --dev
Run All Tests
# Run all tests with coverage
pytest
# Run with verbose output
pytest -v
# Run with coverage report
pytest --cov=bot --cov=main --cov-report=html
Run Specific Test Categories
# Run only unit tests
pytest test_bot.py
# Run only integration tests
pytest test_integration.py
# Run tests matching a pattern
pytest -k "test_parse_feed"
Run with Markers
# Run only unit tests (using markers)
pytest -m unit
# Run only integration tests
pytest -m integration
# Skip slow tests
pytest -m "not slow"
Coverage Reports
# Generate HTML coverage report
pytest --cov=bot --cov=main --cov-report=html
# View report
open htmlcov/index.html # macOS
xdg-open htmlcov/index.html # Linux
GitHub Actions CI/CD
Tests run automatically on every push to main and on all pull requests via .github/workflows/test.yml.
Test Jobs
-
Unit Tests
- Runs on Python 3.10, 3.11, 3.12
- Executes all unit tests
- Uploads coverage to Codecov
-
Integration Tests
- Runs on Python 3.10, 3.11, 3.12
- Executes all integration tests with mocked external services
- Uploads coverage to Codecov
-
Code Quality
- Runs ruff check for linting
- Runs ruff format for code formatting checks
- Runs mypy for type checking
-
Docker Build Test
- Builds the Docker image
- Verifies Python and dependencies are installed
- Ensures the image can run
-
All Tests Pass
- Final job that requires all previous jobs to succeed
- Provides a single status check
Test Coverage Requirements
- Minimum coverage: 80%
- Coverage is measured for
bot.pyandmain.py - Test files are excluded from coverage metrics
Code Quality Standards
Flake8
- Maximum line length: 127 characters
- Maximum cyclomatic complexity: 10
- Critical error codes checked: E9, F63, F7, F82
Black
- Line length: 88 characters (default)
- All Python files must pass black formatting
Mypy
- Type hints encouraged but not required
- Runs in non-strict mode with missing imports ignored
Test Data and Fixtures
Mock RSS Feeds
Integration tests use realistic RSS 2.0 and Atom feed XML for testing feed parsing.
Mock Mastodon API
The Mastodon API is mocked using unittest.mock to avoid making real API calls.
Temporary State Files
Tests use tempfile.mktemp() to create temporary state files that are cleaned up after each test.
Writing New Tests
Unit Test Template
import unittest
from unittest.mock import Mock, patch
from bot import MastodonRSSBot
class TestNewFeature(unittest.TestCase):
def setUp(self):
"""Set up test fixtures"""
self.bot = MastodonRSSBot(
client_id='test',
client_secret='test',
access_token='test',
instance_url='https://test.com',
feed_url='https://feed.test/rss.xml',
state_file='/tmp/test_state.txt'
)
def test_feature(self):
"""Test description"""
result = self.bot.some_method()
self.assertEqual(result, expected_value)
Integration Test Template
import unittest
import responses
from bot import MastodonRSSBot
class TestNewIntegration(unittest.TestCase):
@responses.activate
@patch('bot.Mastodon')
def test_integration(self, mock_mastodon):
"""Test description"""
# Mock HTTP responses
responses.add(
responses.GET,
'https://example.com/feed.xml',
body=rss_xml,
status=200
)
# Run test
bot = MastodonRSSBot(...)
result = bot.process_new_entries()
self.assertEqual(result, expected)
Continuous Integration Status
Troubleshooting
Tests Fail Locally But Pass in CI
- Ensure you're using the same Python version
- Check that all dependencies are installed:
uv sync - Clear pytest cache:
pytest --cache-clear
Coverage Below 80%
- Identify untested code:
pytest --cov=bot --cov-report=term-missing - Add tests for the missing lines
- Some error handling paths may be acceptable to skip
Import Errors
- Ensure the project root is in PYTHONPATH
- Run tests from the project root directory
- Check virtual environment is activated
Best Practices
- Test One Thing: Each test should verify one specific behavior
- Clear Names: Test names should describe what they're testing
- Arrange-Act-Assert: Structure tests with setup, execution, and verification
- Mock External Services: Never make real HTTP requests or API calls
- Clean Up: Always clean up temporary files and state
- Test Edge Cases: Test both happy paths and error conditions
- Keep Tests Fast: Unit tests should run in milliseconds
- Document Complex Tests: Add comments explaining non-obvious test logic