Model/recommendations/tests/test_wall_recommendations.py
Khalim Conn-Kowlessar 316623454a fixed unit tests
2026-03-27 00:15:36 +00:00

528 lines
24 KiB
Python

import pytest
import numpy as np
from unittest.mock import Mock, MagicMock
from recommendations.WallRecommendations import WallRecommendations
from backend.Property import Property
from recommendations.recommendation_utils import is_diminishing_returns
from recommendations.tests.test_data.materials import materials
from etl.epc.Record import EPCRecord
class TestWallRecommendations:
@pytest.fixture
def mock_wall_rec_instance(self):
# Creating a mock instance of WallRecommendations with the necessary attributes
property_mock = Mock()
epc_record = EPCRecord()
epc_record.construction_age_band = "1950"
epc_record.county = "Derbyshire"
epc_record.lodgement_date = "2000-01-01"
property_mock.epc_record = epc_record
property_mock.full_sap_epc = {"lodgement-date": "2000-01-01"}
mock_wall_rec_instance = WallRecommendations(
property_mock, materials=materials
)
return mock_wall_rec_instance
def test_init(self):
p = Mock(
id=1,
insulation_wall_area=100,
walls={
'original_description': 'Average thermal transmittance 0.16 W/m-¦K', 'thermal_transmittance': 0.16,
'thermal_transmittance_unit': 'w/m-¦k', 'is_cavity_wall': False, 'is_filled_cavity': False,
'is_solid_brick': False, 'is_system_built': False, 'is_timber_frame': False,
'is_granite_or_whinstone': False, 'is_as_built': False, 'is_cob': False, 'is_assumed': False,
'is_sandstone_or_limestone': False, 'insulation_thickness': None, 'external_insulation': False,
'internal_insulation': False
},
already_installed=[],
data={"county": "Greater London Authority"}
)
obj = WallRecommendations(
property_instance=p,
materials=materials
)
assert obj
assert obj.property
def test_uvalue_0_16(self):
"""
This tests the wall description Average thermal transmittance 0.16 W/m-¦K
The important data for this recommendation is:
- u value of 0.16
- property built in 2014
Since epc built after 1990 are typically built with insulation and this property
already has really good insulation, we do NOT recommend any measures for this property
"""
p = Mock(
id=1,
insulation_wall_area=100,
year_built=2014,
in_conservation_area=None,
restricted_measure=False,
walls={
'original_description': 'Average thermal transmittance 0.16 W/m-¦K',
'clean_description': 'Average thermal transmittance 0.16 W/m-¦K',
'thermal_transmittance': 0.16,
'thermal_transmittance_unit': 'w/m-¦k', 'is_cavity_wall': False, 'is_filled_cavity': False,
'is_solid_brick': False, 'is_system_built': False, 'is_timber_frame': False,
'is_granite_or_whinstone': False, 'is_as_built': False, 'is_cob': False, 'is_assumed': False,
'is_sandstone_or_limestone': False, 'insulation_thickness': None, 'external_insulation': False,
'internal_insulation': False
},
already_installed=[],
data={"county": "Greater London Authority", 'transaction-type': 'new dwelling'}
)
recommender = WallRecommendations(
property_instance=p,
materials=materials
)
assert recommender.property.walls["original_description"] == "Average thermal transmittance 0.16 W/m-¦K"
recommender.recommend()
# This should be empty
assert recommender.recommendations == []
def test_solid_brick_no_insulation(self):
"""
This tests a property with a wall description of Solid brick, as built, no insulation (assumed)
The property was built in 1930, right on the threshold for when cavity walls were introduced
However, we're told this property is solid brik so we assume no cavity.
We're also told that it has no insulation, so we will recommend internal/external wall insulation
This property is not in a conservation area, however it's a flat so we don't recommend external wall insulation
"""
epc_record = EPCRecord()
epc_record.county = "Greater London Authority"
epc_record.property_type = "Flat"
epc_record.walls_energy_eff = "Very Poor"
p = Mock(
id=2,
year_built=1930,
insulation_wall_area=100,
age_band="A",
restricted_measures=False,
already_installed=[],
construction_age_band="England and Wales: 1930-1949",
in_conservation_area="not_in_conservation_area",
non_invasive_recommendations=[],
walls={
'original_description': 'Solid brick, as built, no insulation (assumed)',
"clean_description": "Solid brick, as built, no insulation",
'thermal_transmittance': None,
'thermal_transmittance_unit': None, 'is_cavity_wall': False, 'is_filled_cavity': False,
'is_solid_brick': True, 'is_system_built': False, 'is_timber_frame': False,
'is_granite_or_whinstone': False, 'is_as_built': True, 'is_cob': False, 'is_assumed': True,
'is_sandstone_or_limestone': False, 'insulation_thickness': 'none', 'external_insulation': False,
'internal_insulation': False, 'is_park_home': False
},
epc_record=epc_record,
)
recommender = WallRecommendations(
property_instance=p,
materials=materials
)
assert not recommender.ewi_valid()
recommender.recommend(phase=0)
# This should result in some recommendations, all of which should be internal insulation
assert recommender.recommendations
rec_types = {part["type"] for rec in recommender.recommendations for part in rec["parts"]}
assert rec_types == {"internal_wall_insulation"}
# Check the recommendations provide a u value below the minimum
assert all(
rec["new_u_value"] < WallRecommendations.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE for rec in
recommender.recommendations
)
def test_solid_brick_insulation(self):
"""
This tests a property with a wall description of Solid brick, as built, insulation (assumed)
The property was built in 1991, after cavity walls were introduced
However, we're told this property is solid brik so we assume no cavity.
We're also told that it has some insulation already
Since the walls are already insulated, we don't recommend further measures
This property is not in a conservation area, however it's a flat so we don't recommend external wall insulation
"""
epc_record = EPCRecord()
epc_record.county = "Greater London Authority"
epc_record.property_type = "Flat"
p = Mock(
id=3,
year_built=1991,
restricted_measures=False,
insulation_wall_area=100,
already_installed=[],
in_conservation_area="not_in_conservation_area",
walls={
'original_description': 'Solid brick, as built, insulated (assumed)',
'clean_description': 'Solid brick, as built, insulated',
'thermal_transmittance': None,
'thermal_transmittance_unit': None, 'is_cavity_wall': False, 'is_filled_cavity': False,
'is_solid_brick': True, 'is_system_built': False, 'is_timber_frame': False,
'is_granite_or_whinstone': False, 'is_as_built': True, 'is_cob': False, 'is_assumed': True,
'is_sandstone_or_limestone': False, 'insulation_thickness': 'average', 'external_insulation': False,
'internal_insulation': False
},
epc_record=epc_record
)
recommender = WallRecommendations(
property_instance=p,
materials=materials
)
assert recommender.property.walls["original_description"] == "Solid brick, as built, insulated (assumed)"
assert not recommender.ewi_valid()
assert recommender.estimated_u_value is None
recommender.recommend()
assert not recommender.recommendations
assert not recommender.estimated_u_value
def test_is_diminishing_returns_no_recommendations(self):
# We have no recommendations but the new u value is below the diminishing returns threshold
# however since there are no recommendaions yet, we should include it and say
# it is NOT diminishing
new_u_value = 0.24
assert new_u_value < WallRecommendations.DIMINISHING_RETURNS_U_VALUE
assert not is_diminishing_returns([], new_u_value, None, WallRecommendations.DIMINISHING_RETURNS_U_VALUE)
def test_is_diminishing_returns_diminishing(self):
# We have a recommendation already and the new u value falls below the diminishing returns
# threshold and is also lower than the lowest selected u value, so we should say this IS
# diminishing returns
new_u_value = 0.2
lowest_selected_u_value = 0.23
assert new_u_value < WallRecommendations.DIMINISHING_RETURNS_U_VALUE
assert is_diminishing_returns([Mock()], new_u_value, lowest_selected_u_value,
WallRecommendations.DIMINISHING_RETURNS_U_VALUE)
def test_is_diminishing_returns_is_diminishing(self):
# We have a recommendation already and the new u value falls below the diminishing returns
# threshold and it's lower than the lowest selected u value, so we should say this IS DIMINISHIN
new_u_value = 0.24
lowest_selected_u_value = 0.26
assert new_u_value < WallRecommendations.DIMINISHING_RETURNS_U_VALUE
assert is_diminishing_returns([Mock()], new_u_value, lowest_selected_u_value,
WallRecommendations.DIMINISHING_RETURNS_U_VALUE)
def test_is_diminishing_returns_not_diminishing(self):
# We have a recommendation already and the new u value falls below the diminishing returns
# threshold however it's higher than the lowest selected u value, so we should say this is NOT
# diminishing returns
new_u_value = 0.24
lowest_selected_u_value = 0.22
assert new_u_value < WallRecommendations.DIMINISHING_RETURNS_U_VALUE
assert not is_diminishing_returns([Mock()], new_u_value, lowest_selected_u_value,
WallRecommendations.DIMINISHING_RETURNS_U_VALUE)
def test_is_diminishing_returns_error_in_recommendations(self, mock_wall_rec_instance):
# Testing case where there's an error in recommendations
mock_wall_rec_instance.recommendations = []
with pytest.raises(ValueError):
is_diminishing_returns([], 0.2, 0.24, 0.25)
class TestWallRecommendationsBase:
@pytest.fixture
def property_mock(self):
property_mock = MagicMock(spec=Property)
property_mock.full_sap_epc = {"lodgement-date": "1999-12-31"}
property_mock.in_conservation_area = "not_in_conservation_area"
property_mock.restricted_measures = False
property_mock.insulation_wall_area = 100
epc_record = EPCRecord(county="Derbyshire", property_type="House")
property_mock.epc_record = epc_record
property_mock.walls = {
"is_cob": False,
"is_sandstone_or_limestone": False,
"is_cavity_wall": False
}
return property_mock
@pytest.fixture
def wall_recommendations_instance(self, property_mock):
wall_recommendations_instance = WallRecommendations(
property_mock, materials=materials
)
return wall_recommendations_instance
def test_ewi_valid_in_conservation_area(self, wall_recommendations_instance):
wall_recommendations_instance.property.in_conservation_area = "in_conversation_area"
wall_recommendations_instance.property.restricted_measures = True
assert wall_recommendations_instance.ewi_valid() is False
def test_ewi_valid_is_flat(self, wall_recommendations_instance):
wall_recommendations_instance.property.epc_record.property_type = "Flat"
assert wall_recommendations_instance.ewi_valid() is False
def test_ewi_valid_not_in_conservation_area_and_not_flat(self, wall_recommendations_instance):
wall_recommendations_instance.property.in_conservation_area = "not_in_conversation_area"
wall_recommendations_instance.property.restricted_measures = False
# Set property_type on the EPCRecord directly
wall_recommendations_instance.property.epc_record.property_type = "House"
assert wall_recommendations_instance.ewi_valid() is True
class TestCavityWallRecommensations:
def test_fill_empty_cavity(self):
epc_record = EPCRecord(county="Derbyshire", walls_energy_eff="Very Poor", property_type="House")
input_property = Property(id=1, postcode="F4k3", address="123 fake street", epc_record=epc_record)
input_property.walls = {
'original_description': 'Cavity wall, as built, no insulation (assumed)',
'clean_description': 'Cavity wall, as built, no insulation',
'thermal_transmittance': None, 'thermal_transmittance_unit': None,
'is_cavity_wall': True, 'is_filled_cavity': False, 'is_solid_brick': False,
'is_system_built': False, 'is_timber_frame': False, 'is_granite_or_whinstone': False,
'is_as_built': True, 'is_cob': False, 'is_assumed': True,
'is_sandstone_or_limestone': False, 'is_park_home': False,
'insulation_thickness': 'none', 'external_insulation': False,
'internal_insulation': False
}
input_property.age_band = "C"
input_property.insulation_wall_area = 50
input_property.construction_age_band = "England and Wales: 1930-1949"
input_property.already_installed = []
recommender = WallRecommendations(
property_instance=input_property,
materials=materials
)
assert not recommender.recommendations
recommender.recommend()
assert recommender.recommendations
assert recommender.estimated_u_value == 1.5
assert np.isclose(recommender.recommendations[0]["new_u_value"], 0.35)
assert np.isclose(recommender.recommendations[0]["total"], 925)
def test_fill_partial_filled_cavity(self):
epc_record = EPCRecord(county="County Durham", walls_energy_eff="Poor", property_type="House")
input_property = Property(id=1, postcode="F4k3", address="123 fake street", epc_record=epc_record)
input_property.walls = {
'original_description': 'Cavity wall, as built, partial insulation (assumed)',
'clean_description': 'Cavity wall, as built, partial insulation',
'thermal_transmittance': None, 'thermal_transmittance_unit': None,
'is_cavity_wall': True, 'is_filled_cavity': False, 'is_solid_brick': False,
'is_system_built': False, 'is_timber_frame': False, 'is_granite_or_whinstone': False,
'is_as_built': True, 'is_cob': False, 'is_assumed': True,
'is_sandstone_or_limestone': False, 'is_park_home': False,
'insulation_thickness': 'below average', 'external_insulation': False,
'internal_insulation': False
}
input_property.age_band = "C"
input_property.insulation_wall_area = 50
input_property.construction_age_band = "England and Wales: 1930-1949"
input_property.already_installed = []
recommender = WallRecommendations(
property_instance=input_property,
materials=materials
)
assert not recommender.recommendations
recommender.recommend()
assert recommender.recommendations
assert recommender.estimated_u_value == 1.3
assert np.isclose(recommender.recommendations[0]["new_u_value"], 0.41)
assert np.isclose(recommender.recommendations[0]["total"], 925.0)
def test_system_built_wall(self):
epc_record = EPCRecord(property_type="House", county="Derbyshire", built_form="Detached",
walls_energy_eff="Very Poor")
input_property2 = Property(id=1, postcode="F4k3 2", address="223 fake street", epc_record=epc_record)
input_property2.walls = {
'original_description': 'System built, as built, no insulation (assumed)',
'clean_description': 'System built, as built, no insulation',
'thermal_transmittance': None, 'thermal_transmittance_unit': None,
'is_cavity_wall': False, 'is_filled_cavity': False, 'is_solid_brick': False,
'is_system_built': True, 'is_timber_frame': False, 'is_granite_or_whinstone': False,
'is_as_built': True, 'is_cob': False, 'is_assumed': True,
'is_sandstone_or_limestone': False, 'is_park_home': False,
'insulation_thickness': 'none', 'external_insulation': False,
'internal_insulation': False
}
input_property2.age_band = "F"
input_property2.insulation_wall_area = 120
input_property2.restricted_measures = False
input_property2.construction_age_band = "England and Wales: 1976-1982"
input_property2.already_installed = []
assert input_property2.walls["is_system_built"]
recommender2 = WallRecommendations(
property_instance=input_property2,
materials=materials
)
assert not recommender2.recommendations
recommender2.recommend()
assert recommender2.recommendations
assert len(recommender2.recommendations) == 2
assert recommender2.estimated_u_value == 1
assert np.isclose(recommender2.recommendations[0]["new_u_value"], 0.21)
assert np.isclose(recommender2.recommendations[0]["total"], 35802.0)
def test_timber_frame_wall(self):
epc_record = EPCRecord(property_type="House", county="Derbyshire", built_form="Detached",
walls_energy_eff="Very Poor")
input_property3 = Property(id=1, postcode="F4k3 3", address="323 fake street", epc_record=epc_record)
input_property3.walls = {
'original_description': 'Timber frame, as built, no insulation (assumed)',
'clean_description': 'Timber frame, as built, no insulation',
'thermal_transmittance': None, 'thermal_transmittance_unit': None,
'is_cavity_wall': False, 'is_filled_cavity': False, 'is_solid_brick': False,
'is_system_built': False, 'is_timber_frame': True, 'is_granite_or_whinstone': False,
'is_as_built': True, 'is_cob': False, 'is_assumed': True,
'is_sandstone_or_limestone': False, 'is_park_home': False,
'insulation_thickness': 'none', 'external_insulation': False,
'internal_insulation': False
}
input_property3.age_band = "F"
input_property3.insulation_wall_area = 120
input_property3.restricted_measures = False
input_property3.construction_age_band = "England and Wales: 1976-1982"
input_property3.already_installed = []
recommender3 = WallRecommendations(
property_instance=input_property3,
materials=materials
)
assert not recommender3.recommendations
recommender3.recommend()
assert recommender3.recommendations
assert recommender3.estimated_u_value == 0.45
assert np.isclose(recommender3.recommendations[0]["new_u_value"], 0.17)
assert np.isclose(recommender3.recommendations[0]["total"], 35802.0)
def test_granite_or_whinstone_wall(self):
epc_record = EPCRecord(property_type="House", county="Derbyshire", built_form="Detached",
walls_energy_eff="Very Poor")
input_property4 = Property(id=1, postcode="F4k3 4", address="423 fake street", epc_record=epc_record)
input_property4.walls = {
'original_description': 'Granite or whinstone, as built, no insulation (assumed)',
'clean_description': 'Granite or whinstone, as built, no insulation',
'thermal_transmittance': None, 'thermal_transmittance_unit': None,
'is_cavity_wall': False, 'is_filled_cavity': False, 'is_solid_brick': False,
'is_system_built': False, 'is_timber_frame': False, 'is_granite_or_whinstone': True,
'is_as_built': True, 'is_cob': False, 'is_assumed': True,
'is_sandstone_or_limestone': False, 'is_park_home': False,
'insulation_thickness': 'none', 'external_insulation': False,
'internal_insulation': False
}
input_property4.age_band = "F"
input_property4.insulation_wall_area = 120
input_property4.restricted_measures = False
input_property4.construction_age_band = "England and Wales: 1976-1982"
input_property4.already_installed = []
recommender4 = WallRecommendations(
property_instance=input_property4,
materials=materials
)
assert not recommender4.recommendations
recommender4.recommend()
assert not recommender4.recommendations
def test_cob_wall(self):
epc_record = EPCRecord(property_type="House", county="Derbyshire", built_form="Detached",
walls_energy_eff="Very Poor")
input_property5 = Property(id=1, postcode="F4k3 5", address="523 fake street", epc_record=epc_record)
input_property5.walls = {
'original_description': 'Cob, as built, no insulation (assumed)',
'clean_description': 'Cob, as built, no insulation',
'thermal_transmittance': None, 'thermal_transmittance_unit': None,
'is_cavity_wall': False, 'is_filled_cavity': False, 'is_solid_brick': False,
'is_system_built': False, 'is_timber_frame': False, 'is_granite_or_whinstone': False,
'is_as_built': True, 'is_cob': True, 'is_assumed': True,
'is_sandstone_or_limestone': False, 'is_park_home': False,
'insulation_thickness': 'none', 'external_insulation': False,
'internal_insulation': False
}
input_property5.age_band = "F"
input_property5.insulation_wall_area = 120
input_property5.restricted_measures = False
input_property5.construction_age_band = "England and Wales: 1976-1982"
input_property5.already_installed = []
recommender5 = WallRecommendations(
property_instance=input_property5,
materials=materials
)
assert not recommender5.recommendations
recommender5.recommend()
assert not recommender5.recommendations
def test_sandstone_or_limestone_wall(self):
epc_record = EPCRecord(property_type="House", county="Derbyshire", built_form="Detached",
walls_energy_eff="Very Poor")
input_property6 = Property(id=1, postcode="F4k3 6", address="623 fake street", epc_record=epc_record)
input_property6.walls = {
'original_description': 'Sandstone or limestone, as built, no insulation (assumed)',
'clean_description': 'Sandstone or limestone, as built, no insulation',
'thermal_transmittance': None, 'thermal_transmittance_unit': None,
'is_cavity_wall': False, 'is_filled_cavity': False, 'is_solid_brick': False,
'is_system_built': False, 'is_timber_frame': False, 'is_granite_or_whinstone': False,
'is_as_built': True, 'is_cob': False, 'is_assumed': True,
'is_sandstone_or_limestone': True, 'is_park_home': False,
'insulation_thickness': 'none', 'external_insulation': False,
'internal_insulation': False
}
input_property6.age_band = "F"
input_property6.insulation_wall_area = 120
input_property6.restricted_measures = False
input_property6.construction_age_band = "England and Wales: 1976-1982"
input_property6.already_installed = []
recommender6 = WallRecommendations(
property_instance=input_property6,
materials=materials
)
assert not recommender6.recommendations
recommender6.recommend()
assert not recommender6.recommendations