How to test relation code with Scenario

See also:

In this guide we will see how to test charm code that interacts with Juju relations.

Suppose that we are writing tests for a charm that copies data provided to it via a “foo” relation to its unit databag:

class MyCharm(CharmBase):
    ...

    def _on_foo_relation_changed(self, e):
        rel = e.relation
        rel.data[self.unit]['data'] = rel.data[e.app]['data']

Now we write a scenario test validating this behaviour. We import MyCharm and a few objects from scenario:

from charm import MyCharm
from scenario import Relation, State, Context

Then the test code:

def test_relation_data_copied():
    # IF the remote end has provided data "baz"
    relation = Relation(
            endpoint="foo",
            remote_app_data={"data": "baz"},
        )
    state_in = State(relations=[relation])
    
    # WHEN a foo_relation_changed is fired on MyCharm
    ctx = Context(MyCharm,
                  meta={"name": "foo"})
    state_out = ctx.run(relation.relation_changed_event, state_in)
    
    # THEN the charm has copied the remote-provided data to its local unit databag
    assert state_out.relations[0].local_unit_data == {"data": "baz"}