Skip to content

Commit c972a90

Browse files
committed
test(simulation): add tests inspired by llm_simpy repository
1 parent b4543f5 commit c972a90

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

tests/test_functionaltest.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"""
2+
Functional testing
3+
4+
Functional tests verify that the system or components perform their intended
5+
functionality.
6+
"""
7+
8+
import pytest
9+
10+
from simulation.parameters import (ASUArrivals, RehabArrivals, ASULOS,
11+
RehabLOS, Param)
12+
from simulation.model import Model
13+
14+
15+
@pytest.mark.parametrize("warm_up_period", [(0), (1)])
16+
def test_audit_length(warm_up_period):
17+
"""
18+
Given that we set an audit interval of 1, and that first audit is performed
19+
at time 0, check that the length of the audit list matches the simulation
20+
time (with no warm-up). Also, check that this is suitably reduced when a
21+
warm-up period is implemented.
22+
23+
Parameters
24+
----------
25+
warm_up_period: float
26+
Length of the warm-up period in days.
27+
28+
Notes
29+
-----
30+
Inspired by `results_collection_test1`, `results_collection_test2` and
31+
`test_warm_up` in github.com/pythonhealthdatascience/llm_simpy/.
32+
"""
33+
# Run the model
34+
param = Param(warm_up_period=warm_up_period,
35+
data_collection_period=10)
36+
model = Model(param=param, run_number=0)
37+
model.run()
38+
39+
# Check the length of the audit list
40+
if warm_up_period == 0:
41+
# Should have audits for timepoints 0 to 9 (so length of 10)
42+
assert len(model.audit_list) == model.env.now == 10
43+
elif warm_up_period == 1:
44+
# With warm-up = 1, should have audits for timepoints 2 to 10 (so
45+
# length of 9), as it is wiped at timepoint 1, so drop 0 and 1, but ran
46+
# for one longer, so goes up to 10
47+
assert len(model.audit_list) == model.env.now - warm_up_period - 1 == 9
48+
49+
50+
def test_high_iat():
51+
"""
52+
Extreme value test, setting a very high inter-arrival time for all
53+
patients, and so we expect no arrivals.
54+
55+
Notes
56+
-----
57+
Inspired by `ev_test_2` from github.com/pythonhealthdatascience/llm_simpy/.
58+
"""
59+
# Set high inter-arrival time for all patient types
60+
iat = 10_000_000
61+
param = Param(
62+
asu_arrivals=ASUArrivals(stroke=iat, tia=iat, neuro=iat, other=iat),
63+
rehab_arrivals=RehabArrivals(stroke=iat, neuro=iat, other=iat))
64+
65+
# Run the model
66+
model = Model(param=param, run_number=0)
67+
model.run()
68+
69+
# Check that there are no arrivals
70+
assert len(model.patients) == 0
71+
72+
# Check that the units are empty
73+
assert model.asu_occupancy == 0
74+
assert model.rehab_occupancy == 0
75+
76+
77+
@pytest.mark.parametrize("stroke_no_esd_mean", [(10_000_000), (5)])
78+
def test_long_los(stroke_no_esd_mean):
79+
"""
80+
Extreme value test, setting a very long length of stay for:
81+
1. All patients -> expect no patients to depart the model.
82+
2. All except one type -> expect only those to depart the model (crudely
83+
checked by seeing if occupancy is less than total arrivals).
84+
85+
Notes
86+
-----
87+
Inspired by `ev_test_3` and `test_ev_4` from
88+
github.com/pythonhealthdatascience/llm_simpy/.
89+
"""
90+
# Set high length of stay for all patient types except stroke_no_esd_mean.
91+
# Also, no warm-up period, otherwise arrivals != occupancy (as arrivals
92+
# excludes warm-up, but occupancy does not, if they are still present).
93+
los = 10_000_000
94+
param = Param(
95+
asu_los=ASULOS(stroke_no_esd_mean=stroke_no_esd_mean,
96+
stroke_esd_mean=los,
97+
tia_mean=los,
98+
neuro_mean=los,
99+
other_mean=los),
100+
rehab_los=RehabLOS(stroke_no_esd_mean=stroke_no_esd_mean,
101+
stroke_esd_mean=los,
102+
tia_mean=los,
103+
neuro_mean=los,
104+
other_mean=los),
105+
warm_up_period=0)
106+
107+
# Run the model
108+
model = Model(param=param, run_number=0)
109+
model.run()
110+
111+
# Check that the total arrivals is equal to or less than total occupancy
112+
total_occupancy = model.asu_occupancy + model.rehab_occupancy
113+
if stroke_no_esd_mean == 10_000_000:
114+
assert len(model.patients) == total_occupancy
115+
elif stroke_no_esd_mean == 5:
116+
assert len(model.patients) > total_occupancy
117+
118+
119+
# TODO: test_ev_5/6/7/8 - requires patient counts by unit and patient type

tests/test_unittest.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
"""
22
Unit tests
3+
4+
Unit tests are a type of functional testing that focuses on individual
5+
components (e.g. methods, classes) and tests them in isolation to ensure they
6+
work as intended.
37
"""
48

59
from collections import namedtuple
@@ -11,6 +15,7 @@
1115
ASUArrivals, RehabArrivals, ASULOS, RehabLOS,
1216
ASURouting, RehabRouting, Param)
1317
from simulation.model import Model
18+
from simulation.runner import Runner
1419

1520

1621
# -----------------------------------------------------------------------------
@@ -124,3 +129,50 @@ def test_run_time():
124129
model.run()
125130
assert model.env.now == 21
126131
assert len(model.patients) > 0
132+
133+
134+
# -----------------------------------------------------------------------------
135+
# Runner
136+
# -----------------------------------------------------------------------------
137+
138+
def test_get_occupancy_freq():
139+
"""
140+
Test the `get_occupancy_freq` method works as expected.
141+
142+
Notes
143+
-----
144+
Inspired by `test_result_processing_1` and `test_result_processing_2` in
145+
github.com/pythonhealthdatascience/llm_simpy/.
146+
"""
147+
# Create test data
148+
audit_list = []
149+
for count, value in [(4, 1), (3, 2), (2, 3), (1, 4)]:
150+
for _ in range(count):
151+
audit_list.append({"asu_occupancy": value,
152+
"rehab_occupancy": value + 1})
153+
154+
# Define expected values for our test data
155+
expected_beds = [1, 2, 3, 4]
156+
expected_freq = [4, 3, 2, 1]
157+
expected_pct = [0.4, 0.3, 0.2, 0.1]
158+
expected_c_pct = [0.4, 0.7, 0.9, 1.0]
159+
expected_prob_delay = [1.0, 0.3/0.7, 0.2/0.9, 0.1/1.0]
160+
161+
# Create a Runner instance
162+
runner = Runner(None)
163+
164+
# Call the method
165+
result_df = runner.get_occupancy_freq(audit_list, "asu")
166+
167+
# Check the structure of the DataFrame
168+
assert list(result_df.columns) == [
169+
"beds", "freq", "pct", "c_pct", "prob_delay"]
170+
171+
# Check the values
172+
assert list(result_df["beds"]) == expected_beds
173+
assert list(result_df["freq"]) == expected_freq
174+
assert np.allclose(result_df["pct"], expected_pct)
175+
assert np.allclose(result_df["c_pct"], expected_c_pct)
176+
177+
# Check prob_delay calculation
178+
assert np.allclose(result_df["prob_delay"], expected_prob_delay)

0 commit comments

Comments
 (0)