Testing Guide¶
Comprehensive testing guide for ccdakit.
Test Organization¶
tests/
├── test_core/ # Core functionality
├── test_protocols/ # Protocol tests
├── test_builders/ # Builder tests
│ ├── test_document.py
│ ├── test_sections/
│ └── test_entries/
├── test_validators/ # Validation tests
├── test_utils/ # Utility tests
└── test_integration/ # Integration tests
Running Tests¶
Basic Commands¶
# All tests
pytest
# Specific file
pytest tests/test_builders/test_document.py
# Specific test
pytest tests/test_builders/test_document.py::TestClinicalDocument::test_basic_document
# With coverage
pytest --cov=ccdakit --cov-report=html
# Parallel execution
pytest -n auto
Test Markers¶
# Unit tests only
pytest -m unit
# Integration tests
pytest -m integration
# Validation tests (require schemas)
pytest -m validation
# Skip slow tests
pytest -m "not slow"
Writing Tests¶
Unit Test Example¶
import pytest
from datetime import date
from ccdakit import ProblemsSection, CDAVersion
class TestProblemsSection:
def test_basic_section(self):
"""Test basic problems section creation."""
# Arrange
class Problem:
@property
def name(self):
return "Diabetes"
@property
def code(self):
return "73211009"
@property
def code_system(self):
return "SNOMED"
@property
def status(self):
return "active"
@property
def onset_date(self):
return date(2020, 1, 1)
problems = [Problem()]
# Act
section = ProblemsSection(
problems=problems,
version=CDAVersion.R2_1
)
element = section.build()
# Assert
assert element is not None
assert element.tag.endswith("section")
Integration Test Example¶
@pytest.mark.integration
def test_complete_document_generation():
"""Test complete C-CDA document generation."""
from ccdakit import ClinicalDocument, ProblemsSection
# Create full document
doc = ClinicalDocument(
patient=patient,
sections=[
ProblemsSection(problems=problems, version=CDAVersion.R2_1),
],
version=CDAVersion.R2_1,
)
# Generate XML
xml = doc.to_string()
# Validate structure
assert "<?xml" in xml
assert "ClinicalDocument" in xml
assert "section" in xml
Validation Test Example¶
@pytest.mark.validation
def test_xsd_validation():
"""Test XSD validation of generated document."""
from ccdakit.validators import XSDValidator
# Generate document
xml = doc.to_string()
# Validate
validator = XSDValidator()
result = validator.validate(xml)
# Check result
assert result.is_valid
assert len(result.issues) == 0
Test Fixtures¶
Common Fixtures¶
import pytest
from datetime import date
@pytest.fixture
def sample_patient():
"""Sample patient for testing."""
class Patient:
@property
def first_name(self):
return "John"
@property
def last_name(self):
return "Doe"
@property
def date_of_birth(self):
return date(1970, 1, 1)
@property
def sex(self):
return "M"
return Patient()
@pytest.fixture
def sample_problem():
"""Sample problem for testing."""
class Problem:
@property
def name(self):
return "Diabetes"
@property
def code(self):
return "73211009"
@property
def code_system(self):
return "SNOMED"
@property
def status(self):
return "active"
@property
def onset_date(self):
return date(2020, 1, 1)
return Problem()
Using Fixtures¶
def test_with_fixtures(sample_patient, sample_problem):
"""Test using fixtures."""
doc = ClinicalDocument(
patient=sample_patient,
sections=[
ProblemsSection(
problems=[sample_problem],
version=CDAVersion.R2_1
),
],
)
assert doc is not None
Coverage¶
Generate Coverage Report¶
# HTML report
pytest --cov=ccdakit --cov-report=html
# Terminal report
pytest --cov=ccdakit --cov-report=term-missing
# XML for CI
pytest --cov=ccdakit --cov-report=xml
Coverage Configuration¶
In pyproject.toml:
[tool.coverage.run]
source = ["ccdakit"]
omit = ["tests/*", "examples/*"]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
]
Continuous Integration¶
GitHub Actions Example¶
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install uv
uv sync --all-extras
- name: Run tests
run: pytest --cov=ccdakit
- name: Upload coverage
uses: codecov/codecov-action@v3
Best Practices¶
- Test naming: Use descriptive names (test_what_when_expected)
- Arrange-Act-Assert: Follow AAA pattern
- One assertion per test: Keep tests focused
- Use fixtures: Reduce duplication
- Mock external dependencies: Keep tests fast
- Test edge cases: Null, empty, invalid inputs
- Document complex tests: Add docstrings