When making a contribution to opsdroid, it’s important that tests are written to validate that the functionality works, and continues to work in the future.

opsdroid is currently slowly migrating from unittest to pytest as it’s testing framework. This work is tracked in issue #1502. As a part of this migration tests can be found in one of two places, old unittest tests are found in the tests/ directory in the root of the repository and new pytest tests are found in a tests/ directory in the same subfolder as the code, i.e opsdroid/tests/.

Writing new tests with pytest

As well as core pytest, opsdroid is making use of a few different pytest plugins:

  • pytest-asyncio for writing and running coroutines as tests. Coroutines should be decorated with @pytest.mark.asyncio.

  • pytest-mock for proving a convenient interface to mocking parts of the code. This package is configured to use the external mock package, so all versions of Python can use the latest features.

An example test

Below is an example test, using the pytest-mock, pytest-asyncio and a fixture.

from opsdroid.memory import Memory
from opsdroid.database import InMemoryDatabase

def memory():
    mem = Memory()
    mem.databases = [InMemoryDatabase()]
    return mem

async def test_database_callouts(mocker, memory):
    memory.databases = [mocker.AsyncMock()]
    data = "Hello world!"

    await memory.put("test", data)
    assert memory.databases[0].put.called

A pytest fixture sets up an object once per test, making sure that the state is clean for every test that uses it. It can also perform teardown actions after a yield statement.

The mocker fixture is provided by pytest-mock, and provides convenient access to things in the mock library, as well as automatic teardown of patches added with mocker.patch.

opsdroid test helpers

Testing utilities.

pytest Fixtures


Fixture with a plain instance of opsdroid.

Will yield an instance of opsdroid.core.OpsDroid which hasn’t been loaded.

Return type