Skip to content

Commit 356fb22

Browse files
marcarlclaude
andcommitted
Migrera testerna till pytest med moderna testmetoder
- Ersätt print-baserade tester med riktiga assertions - Använd parametriserade tester för bättre täckning - Mock:a alla externa API-anrop med requests-mock - Lägg till pytest-konfiguration i pyproject.toml - Skapa GitHub Actions workflow för CI/CD - Alla 40 tester passerar (100% framgång) Tester körs nu automatiskt vid push/PR och använder: - Test markers (unit, integration, api, slow) - Coverage tracking (13% för närvarande) - Mockade Riksdagen API-svar - pytest fixtures för delad testdata 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent feb49fe commit 356fb22

7 files changed

Lines changed: 812 additions & 297 deletions

File tree

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
name: Run Tests
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch: # Allow manual trigger
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
test:
15+
runs-on: ubuntu-latest
16+
strategy:
17+
matrix:
18+
python-version: ["3.10", "3.11", "3.12"]
19+
fail-fast: false # Continue other versions if one fails
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
25+
- name: Set up Python ${{ matrix.python-version }}
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: ${{ matrix.python-version }}
29+
cache: 'pip' # Cache pip dependencies
30+
31+
- name: Install dependencies
32+
run: |
33+
python -m pip install --upgrade pip
34+
pip install -r requirements.txt
35+
pip install pytest pytest-cov pytest-mock requests-mock
36+
37+
- name: Run unit tests
38+
run: |
39+
pytest -v -m "unit" --cov=. --cov-report=term-missing --cov-report=xml
40+
env:
41+
PYTHONPATH: ${{ github.workspace }}
42+
43+
- name: Run integration tests
44+
run: |
45+
pytest -v -m "integration" --cov=. --cov-append --cov-report=term-missing --cov-report=xml
46+
env:
47+
PYTHONPATH: ${{ github.workspace }}
48+
49+
- name: Run API tests
50+
run: |
51+
pytest -v -m "api" --cov=. --cov-append --cov-report=term-missing --cov-report=xml
52+
env:
53+
PYTHONPATH: ${{ github.workspace }}
54+
55+
- name: Run all unmarked tests
56+
run: |
57+
pytest -v -m "not slow" --cov=. --cov-append --cov-report=term-missing --cov-report=xml
58+
env:
59+
PYTHONPATH: ${{ github.workspace }}
60+
61+
- name: Generate coverage report
62+
if: always()
63+
run: |
64+
python -m pip install coverage
65+
coverage report --show-missing || true
66+
67+
- name: Upload coverage artifact
68+
if: matrix.python-version == '3.10'
69+
uses: actions/upload-artifact@v4
70+
with:
71+
name: coverage-report
72+
path: |
73+
coverage.xml
74+
htmlcov/
75+
retention-days: 30

pyproject.toml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
[build-system]
2+
requires = ["setuptools>=45", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "sfs-processor"
7+
version = "0.1.0"
8+
description = "Swedish legal document processor"
9+
readme = "README.md"
10+
requires-python = ">=3.10"
11+
dependencies = [
12+
"requests>=2.25.0",
13+
"pyyaml>=6.0",
14+
"markdown>=3.4.0",
15+
]
16+
17+
[project.optional-dependencies]
18+
test = [
19+
"pytest>=7.4.0",
20+
"pytest-cov>=4.1.0",
21+
"pytest-mock>=3.12.0",
22+
"requests-mock>=1.11.0",
23+
]
24+
25+
[tool.pytest.ini_options]
26+
# Test discovery
27+
testpaths = ["test"]
28+
python_files = ["test_*.py", "*_test.py"]
29+
python_classes = ["Test*"]
30+
python_functions = ["test_*"]
31+
32+
# Output options
33+
addopts = [
34+
"-v", # Verbose output
35+
"--tb=short", # Shorter traceback format
36+
"--strict-markers", # Error on unknown markers
37+
"--color=yes", # Colored output
38+
"-ra", # Show summary of all test outcomes
39+
"--cov=.", # Coverage for all modules
40+
"--cov-report=term-missing", # Show missing lines in coverage
41+
"--cov-report=html:htmlcov", # HTML coverage report
42+
"--cov-branch", # Branch coverage
43+
]
44+
45+
# Markers for test categorization
46+
markers = [
47+
"unit: Unit tests that don't require external resources",
48+
"integration: Integration tests that test multiple components",
49+
"api: Tests that interact with external APIs (mocked)",
50+
"slow: Tests that take significant time to run",
51+
]
52+
53+
# Coverage settings
54+
[tool.coverage.run]
55+
source = ["."]
56+
omit = [
57+
"test/*",
58+
"*/test_*",
59+
"*/__pycache__/*",
60+
"*/site-packages/*",
61+
".venv/*",
62+
"venv/*",
63+
]
64+
65+
[tool.coverage.report]
66+
exclude_lines = [
67+
"pragma: no cover",
68+
"def __repr__",
69+
"raise AssertionError",
70+
"raise NotImplementedError",
71+
"if __name__ == .__main__.:",
72+
"if TYPE_CHECKING:",
73+
]

test/conftest.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""
2+
Shared pytest fixtures and configuration for sfs-processor tests.
3+
"""
4+
import pytest
5+
from pathlib import Path
6+
7+
8+
@pytest.fixture
9+
def project_root():
10+
"""Return the project root directory."""
11+
return Path(__file__).parent.parent
12+
13+
14+
@pytest.fixture
15+
def test_data_dir(project_root):
16+
"""Return the test data directory."""
17+
return project_root / "test" / "data"
18+
19+
20+
@pytest.fixture
21+
def sample_temporal_title():
22+
"""Sample temporal title with date markers for testing."""
23+
return """/Rubriken upphör att gälla U:2025-07-15/
24+
Förordning (2023:30) om statsbidrag till regioner för åtgärder för att höja driftsäkerheten på hälso- och sjukvårdens fastigheter
25+
/Rubriken träder i kraft I:2025-07-15/
26+
Förordning om statsbidrag till regioner för åtgärder för att höja driftsäkerheten på fastigheter för hälso- och sjukvård"""
27+
28+
29+
@pytest.fixture
30+
def sample_sfs_document():
31+
"""Sample SFS document data for testing."""
32+
return {
33+
'beteckning': '2023:30',
34+
'rubrik': """/Rubriken upphör att gälla U:2025-07-15/
35+
Förordning (2023:30) om statsbidrag till regioner för åtgärder för att höja driftsäkerheten på hälso- och sjukvårdens fastigheter
36+
/Rubriken träder i kraft I:2025-07-15/
37+
Förordning om statsbidrag till regioner för åtgärder för att höja driftsäkerheten på fastigheter för hälso- och sjukvård""",
38+
'fulltext': {
39+
'innehall': 'Test innehåll här...'
40+
}
41+
}
42+
43+
44+
@pytest.fixture
45+
def mock_riksdagen_responses(requests_mock):
46+
"""
47+
Mock common Riksdagen API responses.
48+
Can be customized per test by accessing the requests_mock fixture.
49+
"""
50+
# Mock successful proposition (prop 2024/25:1 -> HB031)
51+
requests_mock.get(
52+
'https://data.riksdagen.se/dokument/HB031.json',
53+
json={
54+
'dokumentstatus': {
55+
'dokument': {
56+
'dokumentnamn': 'Prop. 2024/25:1',
57+
'titel': 'Budgetpropositionen för 2025',
58+
'rm': '2024/25',
59+
'beteckning': '1',
60+
'typ': 'prop',
61+
'dokument_url_html': 'https://data.riksdagen.se/dokument/HB031.html'
62+
}
63+
}
64+
}
65+
)
66+
67+
# Mock successful proposition (prop 2023/24:144 -> HA03144)
68+
requests_mock.get(
69+
'https://data.riksdagen.se/dokument/HA03144.json',
70+
json={
71+
'dokumentstatus': {
72+
'dokument': {
73+
'dokumentnamn': 'Prop. 2023/24:144',
74+
'titel': 'Test proposition',
75+
'rm': '2023/24',
76+
'beteckning': '144',
77+
'typ': 'prop',
78+
'dokument_url_html': 'https://data.riksdagen.se/dokument/HA03144.html'
79+
}
80+
}
81+
}
82+
)
83+
84+
# Mock successful bet (committee report) (bet 2023/24:JuU3 -> HA01JuU3)
85+
requests_mock.get(
86+
'https://data.riksdagen.se/dokument/HA01JuU3.json',
87+
json={
88+
'dokumentstatus': {
89+
'dokument': {
90+
'dokumentnamn': 'Bet. 2023/24:JuU3',
91+
'titel': 'Justitieutskottets betänkande',
92+
'rm': '2023/24',
93+
'beteckning': 'JuU3',
94+
'typ': 'bet',
95+
'dokument_url_html': 'https://data.riksdagen.se/dokument/HA01JuU3.html'
96+
}
97+
}
98+
}
99+
)
100+
101+
# Mock riksdagsskrivelse (rskr 2023/24:9 -> HA049)
102+
requests_mock.get(
103+
'https://data.riksdagen.se/dokument/HA049.json',
104+
json={
105+
'dokumentstatus': {
106+
'dokument': {
107+
'dokumentnamn': 'Rskr. 2023/24:9',
108+
'titel': 'Riksdagens skrivelse',
109+
'rm': '2023/24',
110+
'beteckning': '9',
111+
'typ': 'rskr',
112+
'dokument_url_html': 'https://data.riksdagen.se/dokument/HA049.html'
113+
}
114+
}
115+
}
116+
)
117+
118+
return requests_mock
119+
120+
121+
@pytest.fixture
122+
def mock_riksdagen_404(requests_mock):
123+
"""Mock a 404 response from Riksdagen API."""
124+
requests_mock.get(
125+
'https://data.riksdagen.se/dokument/G60340.json',
126+
status_code=404
127+
)
128+
return requests_mock

0 commit comments

Comments
 (0)