labthings_fastapi.testing

Test harnesses to help with writitng tests for things..

Attributes

Params

ReturnType

ThingSubclass

Classes

MockThingServerInterface

A mock class that simulates a ThingServerInterface without the server.

Functions

create_thing_without_server(→ ThingSubclass)

Create a Thing and supply a mock ThingServerInterface.

mock_thing_instance(→ ThingSubclass)

Create a mock Thing instance, with some important attributes.

_mock_slots(→ None)

Mock the slots of a thing created by create_thing_without_server.

use_dummy_url_for(→ collections.abc.Iterator[None])

Use the dummy URL for function in the context variable.

Module Contents

labthings_fastapi.testing.Params
labthings_fastapi.testing.ReturnType
class labthings_fastapi.testing.MockThingServerInterface(name: str, settings_folder: str | None = None, enable_global_lock: bool = False)

Bases: labthings_fastapi.thing_server_interface.ThingServerInterface

A mock class that simulates a ThingServerInterface without the server.

This allows a Thing to be instantiated but not connected to a server. The methods normally provided by the server are mocked, specifically:

  • The name is set by an argument to __init__.

  • start_async_task_soon silently does nothing, i.e. the async function will not be run.

  • The settings folder will either be specified when the class is initialised, or a temporary folder will be created.

  • get_thing_states will return an empty dictionary.

Initialise a ThingServerInterface.

Parameters:
  • name – The name of the Thing we’re providing an interface to.

  • settings_folder – The location where we should save settings. By default, this is a temporary directory.

  • enable_global_lock – Whether to create a global lock object, to mock the server setting of the same name.

_name: str
_settings_tempdir: tempfile.TemporaryDirectory | None = None
_settings_folder = None
_global_lock
_mocks: list[unittest.mock.Mock] = []
start_async_task_soon(async_function: Callable[Params, Awaitable[ReturnType]], *args: Any) concurrent.futures.Future[ReturnType]

Do nothing, as there’s no event loop to use.

This returns a concurrent.futures.Future object that is already cancelled, in order to avoid accidental hangs in test code that attempts to wait for the future object to resolve. Cancelling it may cause errors if you need the return value.

If you need the async code to run, it’s best to add the Thing to a lt.ThingServer instead. Using a test client will start an event loop in a background thread, and allow you to use a real ThingServerInterface without the overhead of actually starting an HTTP server.

Parameters:
  • async_function – the asynchronous function to call.

  • *args – positional arguments to be provided to the function.

Returns:

a concurrent.futures.Future object that has been cancelled.

property settings_folder: str

The path to a folder where persistent files may be saved.

This will create a temporary folder the first time it is called, and return the same folder on subsequent calls.

Returns:

the path to a temporary folder.

property path: str

The path, relative to the server’s base URL, of the Thing.

A ThingServerInterface is specific to one Thing, so this path points to the base URL of the Thing, i.e. the Thing Description’s endpoint.

get_thing_states() Mapping[str, Any]

Return an empty dictionary to mock the metadata dictionary.

Returns:

an empty dictionary.

property _action_manager: labthings_fastapi.actions.ActionManager
Abstractmethod:

Raise an error, as there’s no action manager without a server.

Raises:

NotImplementedError – always.

property application_config: None

Return an empty application configuration when mocking.

Returns:

None

property global_lock: labthings_fastapi.global_lock.GlobalLock | None

Return a global lock.

labthings_fastapi.testing.ThingSubclass
labthings_fastapi.testing.create_thing_without_server(cls: type[ThingSubclass], *args: Any, settings_folder: str | None = None, mock_all_slots: bool = False, enable_global_lock: bool = True, **kwargs: Any) ThingSubclass

Create a Thing and supply a mock ThingServerInterface.

This function is intended for use in testing, where it will enable a Thing to be created without a server, by supplying a MockThingServerInterface instead of a real ThingServerInterface.

The name of the Thing will be taken from the class name, lowercased.

Parameters:
  • cls – The Thing subclass to instantiate.

  • *args – positional arguments to __init__.

  • settings_folder – The path to the settings folder. A temporary folder is used by default.

  • mock_all_slots – Set to True to create a unittest.mock.Mock object connected to each thing slot. It follows the default of the specified to the slot. So if an optional slot has a default of None, no mock will be provided.

  • enable_global_lock – Whether a global lock should be provided.

  • **kwargs – keyword arguments to __init__.

Returns:

an instance of cls with a MockThingServerInterface so that it will function without a server.

Raises:

ValueError – if a keyword argument called ‘thing_server_interface’ is supplied, as this would conflict with the mock interface.

labthings_fastapi.testing.mock_thing_instance(spec: type[ThingSubclass]) ThingSubclass

Create a mock Thing instance, with some important attributes.

Parameters:

spec – the Thing subclass we’re mocking an instance of. Pass lt.Thing if it doesn’t matter.

Returns:

a Mock instance that pretends to be an instance of spec.

labthings_fastapi.testing._mock_slots(thing: labthings_fastapi.thing.Thing) None

Mock the slots of a thing created by create_thing_without_server.

Parameters:

thing – The thing to mock the slots of.

Raises:

TypeError – If this was called on a Thing with a real ThingServerInterface

labthings_fastapi.testing.use_dummy_url_for() collections.abc.Iterator[None]

Use the dummy URL for function in the context variable.