Testing & mocking

Lightbus provides utilities to make testing easier. These utilities allow you to:

  • Ensure only specific events & RPCs were fired
  • Access the sent messages
  • Mock RPC responses

Mocking with events

from lightbus.utilities.testing import BusMocker

from bus import bus

def test_firing_event():
    with BusMocker(bus) as bus_mock:
        # Setup the mocker to expect the auth.user_created was fired.
        # An error will be raised if the tested code fires any other events
        bus_mock.mock_event_firing("auth.user_created")

        # Run the code to be tested
        bus.auth.user_created.fire(field="x")

        # Check the event was fired once
        bus_mock.assert_events_fired("auth.user_created", times=1)

        # Get the fired event message
        message = bus_mock.get_event_messages("auth.user_created")[0]
        assert message.kwargs == {"username": "sarahjane"}

Mocking with RPCs

from lightbus.utilities.testing import BusMocker

from bus import bus

def test_calling_rpc():
    with BusMocker(bus) as bus_mock:
        # Setup the mocker to expect the auth.user_created was fired.
        # An error will be raised if the tested code calls any other RPCs
        bus_mock.mock_rpc_call("auth.check_password", result=True)

        # Run the code to be tested
        bus.auth.check_password(username="sarahjane", password="secret")

        # Check the event was fired once
        bus_mock.assert_rpc_called("auth.check_password", times=1)

        # Get the fired RPC
        message = bus_mock.get_rpc_messages("auth.check_password")[0]
        assert message.kwargs == {"username": "sarahjane", "password": "secret"}

Allowing arbitrary events and RPCs

By default the mocker will raise an error if any event or RPC is fired or called which has not be setup using the mock_event_firing / mock_rpc_call methods.

You can disable this and therefore allow any events or RPCs to the fired/called by using BusMocker(bus, require_mocking=False).

For example, the following will result in no errors even though we have not setup any mocks:

from lightbus.utilities.testing import BusMocker

from bus import bus

def test_permissive_mocking():
    with BusMocker(bus, require_mocking=False) as bus_mock:
        # Neither will cause an error despite the lack of mocking setup.
        # This is because we have set require_mocking=False
        bus.auth.user_created.fire(field="x")
        bus.auth.check_password(username="sarahjane", password="secret")

The @bus_mocker decorator

You can also access the bus mocker using the @bus_mocker decorator. We can rewrite our earlier event example (above) as follows:

from lightbus.utilities.testing import bus_mocker

from bus import bus

@bus_mocker(bus)
def test_firing_event(bus_mock):
    # Setup the mocker to expect the auth.user_created was fired.
    # An error will be raised if the tested code fires any other events
    bus_mock.mock_event_firing("auth.user_created")

    # Run the code to be tested
    bus.auth.user_created.fire(field="x")

    # Check the event was fired once
    bus_mock.assert_events_fired("auth.user_created", times=1)

    # Get the fired event message
    message = bus_mock.get_event_messages("auth.user_created")[0]
    assert message.kwargs == {"username": "sarahjane"}

Testing in Django

You can use the mocker in your Django tests just as shown above. For example, we can access the mocker using the context manager:

from django.test import TestCase
from lightbus.utilities.testing import BusMocker

from bus import bus


class ExampleTestCase(TestCase):

    def test_something(self):
        with BusMocker(bus, require_mocking=False) as bus_mock:
            ...

Or we can use the @bus_mocker decorator:

from django.test import TestCase
from lightbus.utilities.testing import bus_mocker

from bus import bus


class ExampleTestCase(TestCase):

    @bus_mocker(bus)
    def test_something(self, bus_mock):
        ...