4

I've got an Alarm object that uses a Sensor object. In my test I'd like to patch Sensor with a Stub. The code below works, but I have to explicitly pass in the stub to the Alarm constructor:

#tire_pressure_monitoring.py from sensor import Sensor class Alarm: def __init__(self, sensor=None): self._low_pressure_threshold = 17 self._high_pressure_threshold = 21 self._sensor = sensor or Sensor() self._is_alarm_on = False def check(self): psi_pressure_value = self._sensor.sample_pressure() if psi_pressure_value < self._low_pressure_threshold or self._high_pressure_threshold < psi_pressure_value: self._is_alarm_on = True @property def is_alarm_on(self): return self._is_alarm_on #test_tire_pressure_monitoring.py import unittest from unittest.mock import patch, MagicMock, Mock from tire_pressure_monitoring import Alarm from sensor import Sensor class AlarmTest(unittest.TestCase): def test_check_with_too_high_pressure(self): with patch('tire_pressure_monitoring.Sensor') as test_sensor_class: test_sensor_class.instance.sample_pressure.return_value=22 alarm = Alarm(sensor=test_sensor_class.instance) alarm.check() self.assertTrue(alarm.is_alarm_on) 

What I'd like to do, but can't seem to find a way to achieve, is to replace the Sensor instance with a stub, without passing anthing to the Alarm constructor. This code looks to me like it should work, but doesn't:

 def test_check_with_too_high_pressure(self): with patch('tire_pressure_monitoring.Sensor') as test_sensor_class: test_sensor_class.instance.sample_pressure.return_value=22 alarm = Alarm() alarm.check() self.assertTrue(alarm.is_alarm_on) 

The Alarm instance gets an instance of MagicMock, but the 'sample_pressure' method doesn't return 22. Basically I want to know if there is a way to use unittest.mock to test the Alarm class without needing a constructor that takes a Sensor instance as argument.

1 Answer 1

13

When you call test_sensor_class.instance you are using test_sensor_class as a property holder, adding a Mock property instance to which you add a Mock property sample_pressure. Your patch is not used at all, your code is in fact equivalent to:

def test_check_with_too_high_pressure(self): instance = MagicMock() instance.sample_pressure.return_value=22 alarm = Alarm(sensor=instance) alarm.check() self.assertTrue(alarm.is_alarm_on) 

What you want to do it patch the call to Sensor().

Using your code, you simply need to set return value of the mocked class test_sensor_class to a preset mock of Sensor.

def test_check_with_too_high_pressure(self): with patch('tire_pressure_monitoring.Sensor') as test_sensor_class: mockSensor = MagicMock() mockSensor.sample_pressure.return_value = 22 test_sensor_class.return_value = mockSensor alarm = Alarm() alarm.check() self.assertTrue(alarm.is_alarm_on) 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.