This document describes how to run the automated tests for SubScraper.
Install testing dependencies:
pip3 install -r requirements.txtpython3 -m pytest test_main.py -vpython3 -m pytest test_main.py -v --cov=main --cov-report=html# Test job scheduling only
python3 -m pytest test_main.py::TestJobScheduling -v
# Test filtering logic only
python3 -m pytest test_main.py::TestFilterLogic -v
# Test API endpoints only
python3 -m pytest test_main.py::TestAPIEndpoints -vpython3 -m pytest test_main.py::TestJobScheduling::test_count_active_jobs_locked_empty -vThe test suite covers:
- Job slot management: Ensures MAX_RUNNING_JOBS is respected
- Thread safety: Validates no race conditions in concurrent scheduling
- Active job counting: Tests accurate counting of running jobs
- Queue management: Verifies proper job queuing and dequeuing
- Severity filtering: Tests severity level comparisons
- Domain search: Validates case-insensitive domain filtering
- Combined filters: Ensures multiple filters work together
- State payload structure: Validates API response format
- Completed jobs merging: Tests integration of completed scans
- Data consistency: Ensures proper data structure in responses
- CRUD operations: Tests create, read, update, delete
- Foreign keys: Validates cascade deletes
- Data integrity: Ensures consistent database state
- Lock mechanisms: Tests JOB_LOCK prevents race conditions
- ToolGate limits: Validates concurrent access control
- Resource contention: Ensures proper synchronization
- Input validation: Tests domain and subdomain detection
- Error detection: Validates rate limit error identification
- Data sanitization: Tests input cleaning and normalization
test_main.py::TestJobScheduling::test_count_active_jobs_locked_empty PASSED
test_main.py::TestJobScheduling::test_schedule_jobs_respects_max_limit PASSED
...
======================== X passed in Y.YYs ========================
If a test fails, you'll see:
test_main.py::TestJobScheduling::test_count_active_jobs_locked_empty FAILED
=========================== FAILURES ===========================
________________________ test_name ____________________________
[detailed error traceback]
These tests are designed to run in CI/CD pipelines. Example GitHub Actions workflow:
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- run: pip install -r requirements.txt
- run: pytest test_main.py -v --cov=mainIf you see import errors, ensure you're running from the repository root:
cd /path/to/subScraper
python3 -m pytest test_main.py -vIf you see "database is locked" errors, ensure no other instance of SubScraper is running:
# Check for running processes
ps aux | grep main.py
# Kill if necessary
pkill -f main.pySome tests involve threading and may occasionally timeout on slow systems. Increase timeout:
python3 -m pytest test_main.py -v --timeout=60When adding new features, follow these guidelines:
- Create a new test class for each major feature
- Use setup_method to initialize test state
- Use teardown_method to clean up
- Mock external dependencies (network, filesystem, etc.)
- Test edge cases (empty input, invalid data, race conditions)
- Document test purpose with clear docstrings
Example:
class TestNewFeature:
"""Tests for the new feature"""
def setup_method(self):
"""Setup test fixtures"""
self.original_state = save_state()
def teardown_method(self):
"""Restore original state"""
restore_state(self.original_state)
def test_basic_functionality(self):
"""Test that basic feature works"""
result = new_feature_function()
assert result == expected_valueFor performance-critical code, use pytest-benchmark:
pip install pytest-benchmarkExample benchmark test:
def test_scheduling_performance(benchmark):
"""Benchmark job scheduling speed"""
result = benchmark(main.schedule_jobs)
assert result is not NoneAim for:
- Overall coverage: >80%
- Critical paths (job scheduling, thread safety): >95%
- API endpoints: >90%
- Utility functions: >85%
View coverage report:
python3 -m pytest test_main.py --cov=main --cov-report=html
open htmlcov/index.html