-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtest_reform_impacts.py
More file actions
84 lines (64 loc) · 2.71 KB
/
Copy pathtest_reform_impacts.py
File metadata and controls
84 lines (64 loc) · 2.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""
Test suite for PolicyEngine UK reform fiscal impacts.
This file tests that model changes don't unexpectedly change reform impacts.
"""
import pytest
import yaml
from pathlib import Path
from policyengine_uk import Microsimulation
from policyengine_core.data import Dataset
from policyengine_uk_data.storage import STORAGE_FOLDER
# Load configuration from YAML file
config_path = Path(__file__).parent / "reforms_config.yaml"
with open(config_path, "r") as f:
config = yaml.safe_load(f)
reforms_data = config["reforms"]
def get_fiscal_impact(baseline, enhanced_frs, reform: dict) -> float:
"""
Calculate the fiscal impact of a reform in billions.
Args:
reform: Dictionary of reform parameters
Returns:
Fiscal impact in billions (positive = revenue increase)
"""
baseline_revenue = baseline.calculate("gov_balance", 2029).sum()
reform_simulation = Microsimulation(reform=reform, dataset=enhanced_frs)
reform_revenue = reform_simulation.calculate("gov_balance", 2029).sum()
return (reform_revenue - baseline_revenue) / 1e9
# Extract test parameters from configuration
test_params = [
(reform["parameters"], reform["name"], reform["expected_impact"])
for reform in reforms_data
]
reform_names = [reform["name"] for reform in reforms_data]
@pytest.mark.parametrize(
"reform, reform_name, expected_impact",
test_params,
ids=reform_names,
)
def test_reform_fiscal_impacts(
baseline, enhanced_frs, reform, reform_name, expected_impact
):
"""Test that each reform produces the expected fiscal impact."""
impact = get_fiscal_impact(baseline, enhanced_frs, reform)
# Allow for small numerical differences (5.0 billion tolerance)
assert (
abs(impact - expected_impact) < 5.0
), f"Impact for {reform_name} is {impact:.1f} billion, expected {expected_impact:.1f} billion"
def test_config_file_exists():
"""Test that the configuration file exists and is valid."""
assert config_path.exists(), "reforms_config.yaml file not found"
assert "reforms" in config, "reforms key not found in configuration"
assert len(config["reforms"]) > 0, "No reforms defined in configuration"
def test_all_reforms_have_required_fields():
"""Test that all reforms have the required fields."""
required_fields = ["name", "expected_impact", "parameters"]
for i, reform in enumerate(reforms_data):
for field in required_fields:
assert (
field in reform
), f"Reform {i} missing required field: {field}"
assert isinstance(
reform["parameters"], dict
), f"Reform {i} parameters must be a dictionary"
assert len(reform["parameters"]) > 0, f"Reform {i} has no parameters"