Files
AareDAQ/tests/unit/devices/test_my_motor.py
appleb_m 6f44da0078
Build and Publish / test (push) Failing after 1m4s
Build and Publish / build (push) Has been skipped
Build and Publish / Build and Deploy Docs (push) Has been skipped
tests: added tests for aerotech, models, autofocus, automation, beamline, diffraction_geometry, enum_pv, face_detection_find_xtal, jfjoch_client, mlbox, my_motor, spreadsheet_updater and worfkflows
2026-04-28 14:35:54 +02:00

140 lines
5.8 KiB
Python

import pytest
from unittest.mock import MagicMock, patch, PropertyMock
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
m = 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)