Refactor shift constraints in tests to use new constraint classes

- Updated test cases in `test_workers.py` to replace dictionary-based constraints with instances of `PreShiftConstraint`, `PostShiftConstraint`, and `MaxShiftsPerWeekConstraint`.
- Added a new test `test_worker_assign_as_block_preference2` to verify worker preferences for block assignments.
- Marked tests as slow where appropriate to improve test suite performance.
This commit is contained in:
Ross
2025-08-11 13:03:08 +01:00
parent d7bcfce78c
commit 76f3b48c1d
12 changed files with 790 additions and 987 deletions
+60 -32
View File
@@ -1,9 +1,10 @@
import pytest
from rota.shifts import InvalidShift, NoWorkers, RotaBuilder, SingleShift, WarningTermination, WorkerRequirement, days
from rota.shifts import InvalidShift, MaxShiftsPerWeekConstraint, NoWorkers, PostShiftConstraint, RotaBuilder, SingleShift, WarningTermination, WorkerRequirement, days
import datetime
from rota.workers import NonWorkingDays, NotAvailableToWork, Worker, generate_not_available_to_works
from rota.workers import WorkRequests
from web.rota.shifts import PreShiftConstraint
def generate_basic_rota(
weeks_to_rota=10, workers=0, start_date=datetime.date(2022, 3, 7)
@@ -577,9 +578,9 @@ def test_worker_requirement_and_force_block():
days=days[:4],
workers_required=wr,
force_as_block=True,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
SingleShift(
@@ -589,9 +590,9 @@ def test_worker_requirement_and_force_block():
days=days[4:],
workers_required=wr,
force_as_block=True,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
)
@@ -606,6 +607,7 @@ def test_worker_requirement_and_force_block():
assert shift_string.count("cccc") == shift_string.count("c") / 4
assert shift_string.count("ddd") == shift_string.count("d") / 3
@pytest.mark.slow
def test_split_shift():
Rota = generate_basic_rota(workers=11, weeks_to_rota=22)
@@ -620,10 +622,10 @@ def test_split_shift():
length=12.5,
days=days[:4],
workers_required=1,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
{"name": "max_shifts_per_week", "options": 1},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
MaxShiftsPerWeekConstraint(max_shifts=1),
]
),
SingleShift(
@@ -633,9 +635,9 @@ def test_split_shift():
days=(days[4], days[6]),
workers_required=1,
assign_as_block=True,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
SingleShift(
@@ -644,9 +646,9 @@ def test_split_shift():
length=12.5,
days=days[5],
workers_required=1,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
)
@@ -685,7 +687,7 @@ def test_locums_basic():
days=days[:4],
workers_required=1,
constraint=[
constraints=[
#{"name": "pre", "options": 1},
#{"name": "post", "options": 1},
#{"name": "max_shifts_per_week", "options": 1},
@@ -734,7 +736,7 @@ def test_locums_nwds():
days=days[:4],
workers_required=1,
constraint=[
constraints=[
#{"name": "pre", "options": 1},
#{"name": "post", "options": 1},
#{"name": "max_shifts_per_week", "options": 1},
@@ -751,7 +753,6 @@ def test_locums_nwds():
assert Rota.results.solver.status == "ok"
for worker in Rota.get_workers():
print( Rota.get_worker_shift_list(worker))
assert Rota.get_worker_shift_list(worker).count("a") == 4
if worker.name in ("worker03", "worker04"):
@@ -782,7 +783,7 @@ def test_locums_no_availablity():
days=days[:4],
workers_required=1,
constraint=[
constraints=[
#{"name": "pre", "options": 1},
#{"name": "post", "options": 1},
#{"name": "max_shifts_per_week", "options": 1},
@@ -794,6 +795,7 @@ def test_locums_no_availablity():
with pytest.raises(WarningTermination):
Rota.build_and_solve()
@pytest.mark.slow
def test_locums():
Rota = generate_basic_rota(workers=7, weeks_to_rota=10)
@@ -832,10 +834,10 @@ def test_locums():
days=days[:4],
workers_required=1,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
{"name": "max_shifts_per_week", "options": 1},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
MaxShiftsPerWeekConstraint(max_shifts=1),
]
),
SingleShift(
@@ -845,9 +847,9 @@ def test_locums():
days=(days[4], days[6]),
workers_required=1,
assign_as_block=True,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
SingleShift(
@@ -856,9 +858,9 @@ def test_locums():
length=12.5,
days=days[5],
workers_required=1,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
)
@@ -912,11 +914,37 @@ def test_worker_assign_as_block_preference():
shift_list_4 = Rota.get_worker_shift_list_string(worker4)
assert shift_list_4.count("a") == 12, "Worker 4 should have at least 12 'a' shifts, but may not be grouped together"
def test_worker_assign_as_block_preference2():
"""Test that a worker's assign_as_block preference is respected over the global setting."""
Rota = generate_basic_rota(workers=4, weeks_to_rota=8)
# Worker 1 prefers to have shift 'a' assigned as a block, worker 2 does not
workers = Rota.get_workers()
worker1 = workers[0]
worker2 = workers[1]
worker3 = workers[2]
worker4 = workers[3]
# Add a shift 'a' that is NOT globally set as assign_as_block
Rota.add_shifts(
SingleShift(
sites=("group1",),
name="a",
length=8,
days=days[:4],
workers_required=1,
assign_as_block=False, # global setting is off
),
)
# Modify worker1's preference to prevent block 'a' shifts
worker1.assign_as_block_preferences = {"a":-1}
Rota.build_and_solve(options={"ratio": 0.0})
Rota.export_rota_to_html("test_worker_assign_as_block_preference", folder="tests")
shift_list_1 = Rota.get_worker_shift_list_string(worker1)
assert shift_list_1.count("aaaa") == 0, "Worker 1 should have all 'a' shifts grouped together (block)"
assert shift_list_1.count("aaaa") == 0, "Worker 1 should have less 'a' shifts grouped together (block)"
worker1.assign_as_block_preferences = {"a":0}