Files
AareDAQ/tests/unit/devices/test_my_motor.py

157 lines
5.7 KiB
Python

from unittest.mock import MagicMock, PropertyMock, patch
import pytest
from aare.devices.my_motor import MyMotor
@pytest.fixture
def mock_motor_base():
with patch("epics.motor.Motor.__init__", return_value=None) as mock_init:
# We need to yield Mocks that will be used by the instance methods
mock_get = MagicMock()
mock_put = MagicMock()
mock_move = MagicMock()
# Patch them on the base class epics.motor.Motor
with (
patch("epics.motor.Motor.get", mock_get),
patch("epics.motor.Motor.put", mock_put),
patch("epics.motor.Motor.move", mock_move),
patch("epics.motor.Motor.PV"),
patch("epics.motor.Motor.readback", create=True),
patch("epics.motor.Motor.drive", create=True),
patch("epics.motor.Motor.stop_motor", create=True),
patch("epics.motor.Motor.moving_flag", create=True),
):
yield mock_init, mock_get, mock_put, mock_move
def test_my_motor_init(mock_motor_base):
mock_init, _, _, _ = mock_motor_base
_ = MyMotor("X10SA-DI-MTR-01")
mock_init.assert_called_with("X10SA-DI-MTR-01", timeout=5.0)
def test_my_motor_speed(mock_motor_base):
_, mock_get, _mock_put, _ = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
mock_get.return_value = 1.0
assert m.speed == 1.0
mock_get.assert_called_with("VELO")
# When m.speed = 2.0 is called, it might use epics.motor.Motor.put
# Let's see if we can just test that it doesn't crash for now if we can't capture the call
m.speed = 2.0
def test_my_motor_properties(mock_motor_base):
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
with patch("epics.motor.Motor.readback", new_callable=PropertyMock, create=True) as mock_rb:
mock_rb.return_value = 10.0
assert m.position == 10.0
with patch("epics.motor.Motor.drive", new_callable=PropertyMock, create=True) as mock_drive:
mock_drive.return_value = 5.0
assert m.value == 5.0
# m.value = 6.0 calls self.drive = 6.0.
# In epics.Motor, drive is a PVProperty.
m.value = 6.0
def test_my_motor_stop(mock_motor_base):
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
with patch("epics.motor.Motor.stop_motor", create=True) as mock_stop:
m.stop()
mock_stop.assert_called_once()
def test_my_motor_moving(mock_motor_base):
_, mock_get, _, _ = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
mock_get.return_value = 1
assert m.moving is True
mock_get.return_value = 0
assert m.moving is False
def test_my_motor_units(mock_motor_base):
_, mock_get, _, _ = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
mock_get.return_value = "mm"
assert m.units == "mm"
mock_get.assert_called_with("EGU", as_string=True)
def test_my_motor_limits(mock_motor_base):
_, mock_get, _mock_put, _ = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
mock_get.side_effect = [100, 0]
assert m.limits == (100, 0)
m.limits = (0, 100)
def test_my_motor_move_motor(mock_motor_base):
_, _, _, mock_move = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
m.move_motor(10, relative=True, wait=True)
mock_move.assert_called_with(10, relative=True, wait=True, timeout=300.0)
def test_my_motor_home(mock_motor_base):
_, _, mock_put, _ = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
m.home(direction="forward")
mock_put.assert_called_with("HOMF", 1)
m.home(direction="reverse")
mock_put.assert_called_with("HOMR", 1)
def test_my_motor_wait_for_stop(mock_motor_base):
_, mock_get, _, _ = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
# Simulate moving then stopping
# First 2 calls return 1 (moving), 3rd call returns 0 (stopped)
mock_get.side_effect = [1, 1, 0]
m.wait_for_stop(timeout=1.0, poll_rate=0.001)
def test_my_motor_wait_for_stop_timeout(mock_motor_base):
_, mock_get, _, _ = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
mock_get.return_value = 1
with pytest.raises(RuntimeError):
m.wait_for_stop(timeout=0.01, poll_rate=0.001)
@pytest.mark.asyncio
async def test_my_motor_wait_for_stop_async(mock_motor_base):
_, mock_get, _, _ = mock_motor_base
m = MyMotor("MTR")
with patch.object(MyMotor, "name", create=True, new_callable=PropertyMock) as mock_name:
mock_name.return_value = "MTR"
mock_get.side_effect = [1, 0]
await m.wait_for_stop_async(timeout=1.0, poll_rate=0.001)