Testing AppDaemon ================= AppDaemon uses `pytest `_ and `pytest-asyncio `_. - Pytest is configured in the this section in the `pyproject.toml `_ file. .. literalinclude:: ../pyproject.toml :language: toml :lines: 88-96 :caption: Pytest configuration options - Pytest-asyncio manages creating the event loop, which is normally handled by :py:class:`~appdaemon.__main__.ADMain`. The event loop persists throughout the test session and is reused many times by different instantiations of the top-level :py:class:`~appdaemon.appdaemon.AppDaemon` class. - Instantiating the :py:class:`~appdaemon.appdaemon.AppDaemon` class can now be done without any side effects. This will also instantiate the necessary subsystem classes, but nothing will really start happening until the :py:meth:`~appdaemon.appdaemon.AppDaemon.start` method is called. - The :py:class:`~appdaemon.appdaemon.AppDaemon` object is provided as a `pytest fixture `_ (``ad``) with the ``function`` scope, which means it will be recreated fresh for each test function. The fixture handles starting and stopping the :py:class:`~appdaemon.appdaemon.AppDaemon` instance before/after each test. It also disables all apps, so they can be selectively run by the tests. - Apps can be modified before they're run by the :py:class:`~appdaemon.app_management.AppManagement` object. - The ``run_app_for_time`` fixture combines the functionality of the ``ad`` fixture with the :py:meth:`~appdaemon.app_management.AppManagement.app_run_context` so that apps can be temporarily modified and run for short periods. Running Tests ------------- Use the `uv run `_ command to ensure uv handles the environment. It will make sure the dependencies are all satisfied. .. code-block:: console :caption: Run all tests $ uv run pytest CI Tests ~~~~~~~~ The CI tests get run as part of the GitHub action on PRs to the ``dev`` branch. They're intended to each run more or less instantly and collectively only take a few seconds. .. code-block:: console :caption: Run CI tests $ uv run pytest -m ci Functional ~~~~~~~~~~ Functional tests cover various end-to-end interactions between components, so they require AppDaemon to be running. An example would be starting an app, having it register a callback for an event, firing that event, and checking that the callback was called. These should cover as many corner cases as possible .. code-block:: console :caption: Run functional tests $ uv run pytest -m functional Unit Tests ~~~~~~~~~~ Unit tests don't require AppDaemon to be running and should be run frequently during development. Currently the only unit tests are ones that cover datetime and timedelta parsing. .. code-block:: console :caption: Run unit tests $ uv run pytest -m unit Plugin Tests ~~~~~~~~~~~~ Testing plugins involves either connecting to or mocking external systems, so aren't yet covered. Reference --------- Startup Tests ~~~~~~~~~~~~~ .. autofunction:: tests.functional.test_startup.test_hello_world Event Tests ~~~~~~~~~~~ .. autoclass:: tests.functional.test_event.TestEventCallback :members: State Tests ~~~~~~~~~~~ .. autoclass:: tests.functional.test_state.TestStateCallback :members: