`scenario.capture_events`: check events emitted on your charm

Hi!

If your charm deals with deferred events, custom events, and charm libs that in turn emit their own custom events, it can be hard to unit-test the resulting control flow. In these situations it can be useful to verify that, as a result of a given Juju event triggering, a specific chain of deferred and custom events is emitted on the charm. In Scenario tests, the output state, black-box as it is, gives little insight into how exactly it was obtained.

Scenario has just merged a little addition to its toolbox: capture_events, a context manager some of you may already be familiar with (it’s been ripped off of harness-extensions).

scenario.capture_events allows you to open a peephole in the otherwise pretty black State-box and intercept any events emitted by the framework while triggering an event on it.

What this looks like in practice:

from ops.charm import StartEvent
from scenario import Event, State
from charm import MyCharm, MyCustomEvent  # Any custom event types
    
def test_my_event():
    # capture any events of these types:
    captured: List[CharmBase]
    with capture_events(StartEvent, MyCustomEvent) as captured:
        State().trigger("start", MyCharm, meta=MyCharm.META)
    
    # 
    assert len(captured) == 2
    e1, e2 = captured
    assert isinstance(e2, MyCustomEvent)
    assert e2.custom_attr == 'foo'

Read more about it here.