Testing subpackage

This subpackage contains modules for test mocking in the SKA SatLMC tests.

class MockCallable(return_value=None, called_timeout=5.0, not_called_timeout=1.0)

This class implements a mock callable.

It is useful for when you want to assert that a callable is called, but the callback is called asynchronously, so that you might have to wait a short time for the call to occur.

If you use a regular mock for the callback, your tests will end up littered with sleeps:

antenna_apiu_proxy.start_communicating()
communication_state_changed_callback.assert_called_once_with(
    CommunicationStatus.NOT_ESTABLISHED
)
time.sleep(0.1)
communication_state_changed_callback.assert_called_once_with(
    CommunicationStatus.ESTABLISHED
)

These sleeps waste time, slow down the tests, and they are difficult to tune: maybe you only need to sleep 0.1 seconds on your development machine, but what if the CI pipeline deploys the tests to an environment that needs 0.2 seconds for this?

This class solves that by putting each call to the callback onto a queue. Then, each time we assert that a callback was called, we get a call from the queue, waiting if necessary for the call to arrive, but with a timeout:

antenna_apiu_proxy.start_communicating()
communication_state_changed_callback.assert_next_call(
    CommunicationStatus.NOT_ESTABLISHED
)
communication_state_changed_callback.assert_next_call(
    CommunicationStatus.ESTABLISHED
)
__init__(return_value=None, called_timeout=5.0, not_called_timeout=1.0)

Initialise a new instance.

Parameters:
  • return_value (Optional[Any]) – what to return when called

  • called_timeout (float) – how long to wait for a call to occur when we are expecting one. It makes sense to wait a long time for the expected call, as it will generally arrive much much sooner anyhow, and failure for the call to arrive in time will cause the assertion to fail. The default is 5 seconds.

  • not_called_timeout (float) – how long to wait for a callback when we are not expecting one. Since we need to wait the full timeout period in order to determine that a callback has not arrived, asserting that a call has not been made can severely slow down your tests. By keeping this timeout quite short, we can speed up our tests, at the risk of prematurely passing an assertion. The default is 0.5

assert_last_call(*args, **kwargs)

Assert the arguments of the last call to this mock callback.

The “last” call is the last call before an attempt to get the next event times out.

This is useful for situations where we know a device may call a callback several time, and we don’t care too much about the exact order of calls, but we do know what the final call should be.

Parameters:
  • args (Any) – positional args that the call is asserted to have

  • kwargs (Any) – keyword args that the call is asserted to have

Raises:

AssertionError – if the callback has not been called.

Return type:

None

assert_next_call(*args, **kwargs)

Assert the arguments of the next call to this mock callback.

If the call has not been made, this method will wait up to the specified timeout for a call to arrive.

Parameters:
  • args (Any) – positional args that the call is asserted to have

  • kwargs (Any) – keyword args that the call is asserted to have

Raises:

AssertionError – if the callback has not been called.

Return type:

None

assert_not_called(timeout=None)

Assert that the callback still has not been called after the timeout period.

This is a slow method because it has to wait the full timeout period in order to determine that the call is not coming. An optional timeout parameter is provided for the situation where you are happy for the assertion to pass after a shorter wait time.

Parameters:

timeout (Optional[float]) – optional timeout for the check. If not provided, the default is the class setting

Return type:

None

calls_in_queue(expected_arguments_list)

Docstring.

Parameters:

expected_arguments_list (list[Any]) – A list of arguments this mock is expected to be called with and found in the queue.

Return type:

bool

Returns:

True if all arguments provided were found in the queue else returns False.

get_next_call()

Return the arguments of the next call to this mock callback.

This is useful for situations where you do not know exactly what the arguments of the next call will be, so you cannot use the assert_next_call() method. Instead you want to assert some specific properties on the arguments:

(args, kwargs) = mock_callback.get_next_call()
event_data = args[0].attr_value
assert event_data.name == "healthState"
assert event_data.value == HealthState.UNKNOWN
assert event_data.quality == tango.AttrQuality.ATTR_VALID

If the call has not been made, this method will wait up to the specified timeout for a call to arrive.

Raises:

AssertionError – if the callback has not been called

Return type:

tuple[Sequence[Any], dict[str, Any]]

Returns:

an (args, kwargs) tuple

get_whole_queue()

Return the arguments of all calls to this mock callback currently in the queue.

This is useful for situations where you do not know exactly what order the calls will happen but you do know what the arguments will be. Instead you want to assert that your call is somewhere in the queue.

If the call has not been made, this method will wait up to the specified timeout for a call to arrive.

Return type:

list[tuple[Sequence[Any], dict[str, Any]]]

Returns:

a list of (args, kwargs) tuple

class MockChangeEventCallback(event_name, called_timeout=5.0, not_called_timeout=0.5, filter_for_change=False)

This class implements a mock change event callback.

It is a special case of a MockCallable where the callable expects to be called with event_name, event_value and event_quality arguments (which is how ska_sat_lmc.device_proxy.SatDeviceProxy calls its change event callbacks).

__init__(event_name, called_timeout=5.0, not_called_timeout=0.5, filter_for_change=False)

Initialise a new instance.

Parameters:
  • event_name (str) – the name of the event for which this callable is a callback

  • called_timeout (float) – how long to wait for a call to occur when we are expecting one. It makes sense to wait a long time for the expected call, as it will generally arrive much much sooner anyhow, and failure for the call to arrive in time will cause the assertion to fail. The default is 5 seconds.

  • not_called_timeout (float) – how long to wait for a callback when we are not expecting one. Since we need to wait the full timeout period in order to determine that a callback has not arrived, asserting that a call has not been made can severely slow down your tests. By keeping this timeout quite short, we can speed up our tests, at the risk of prematurely passing an assertion. The default is 0.5

  • filter_for_change (bool) – filtered?

assert_last_change_event(value, _do_assert=True, quality=tango.AttrQuality.ATTR_VALID)

Assert the arguments of the last call to this mock callback.

The “last” call is the last call before an attempt to get the next event times out.

This is useful for situations where we know a device may fire several events, and we don’t know or care about the exact order of events, but we do know what the final event should be. For example, when we tell MccsController to turn on, it has to turn many devices on, which have to turn many devices on, etc. With so m

Parameters:
  • value (Any) – the asserted value of the change event

  • quality (AttrQuality) – the asserted quality of the change event. This is optional, with a default of ATTR_VALID.

  • _do_assert (bool) – option to not perform an assert (useful for debugging).

Raises:

AssertionError – if the callback has not been called.

Return type:

None

assert_next_change_event(value, quality=tango.AttrQuality.ATTR_VALID)

Assert the arguments of the next call to this mock callback.

If the call has not been made, this method will wait up to the specified timeout for a call to arrive.

Parameters:
  • value (Any) – the asserted value of the change event

  • quality (AttrQuality) – the asserted quality of the change event. This is optional, with a default of ATTR_VALID.

Raises:

AssertionError – if the callback has not been called.

Return type:

None

assert_not_called()

Assert if not called.

Raises:

AssertionError – change event callback

Return type:

None

get_next_change_event()

Return the attribute value in the next call to this mock change event callback.

This is useful for situations where you do not know exactly what the value will be, so you cannot use the assert_next_change_event() method. Instead you want to assert some specific properties on the arguments.

Raises:

AssertionError – if the callback has not been called

Return type:

Any

Returns:

an (args, kwargs) tuple

class MockDeviceBuilder(from_factory=<class 'unittest.mock.Mock'>)

This module implements a mock builder for tango devices.

__init__(from_factory=<class 'unittest.mock.Mock'>)

Create a new instance.

Parameters:

from_factory (type[Mock]) – an optional factory from which to draw the original mock

add_attribute(name, value)

Tell this builder to build mocks with a given attribute.

TODO: distinguish between read-only and read-write attributes

Parameters:
  • name (str) – name of the attribute

  • value (Any) – the value of the attribute

Return type:

None

add_command(name, return_value)

Tell this builder to build mocks with a specified command.

And that the command returns the provided value.

Parameters:
  • name (str) – name of the command

  • return_value (Any) – what the command should return

Return type:

None

add_result_command(name, result_code, status='Mock information-only message')

Tell this builder to build mocks with a specified command.

And that the command returns (ResultCode, [message, message_uid]) or (ResultCode, message) tuples as required.

Parameters:
  • name (str) – the name of the command

  • result_code (ResultCode) – code indicating the status of the command

  • status (str) – an information-only message for the command to return

Return type:

None

set_state(state)

Tell this builder to build mocks with the state set as specified.

Parameters:

state (DevState) – the state of the mock

Return type:

None