Registry / testing / ops-scenario

ops-scenario

JSON →
library8.7.1pypypi✓ verified 83d ago

A Python library for state-transition testing of Juju charms built with the Operator Framework. Provides the `ops.testing` module with the `Context` API to simulate charm lifecycle events and validate state changes. Current version: 8.7.0 (2026). Requires Python >=3.10. Active development with frequent releases.

pip install ops[testing]
INSTALL
IMPORT
SIG · OPS-SCENARIO
O
ops-scenario
testingpythonv8.7.1
Install
2.2s avg
Import
770ms
Disk
22MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v8.7.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.910 runs
installs and imports cleanly · install 0.0s · import 0.806s · 23.6MB
glibc
py 3.103.910 runs
installs and imports cleanly · install 2.2s · import 0.733s · 25MB
22MB installed
● package 22MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

Context
from ops.testing import Context
from scenario import Context
'scenario' is not a valid module; the correct import is from ops.testing.
State
from ops.testing import State
from ops.scenario import State
State is part of ops.testing, not a separate ops.scenario module.
CharmSpec
from ops.testing import CharmSpec
CharmSpec is available in ops.testing; no common wrong import.

Minimal test: creates a charm, runs the install event, asserts active status.

import os import yaml from ops.charm import CharmBase from ops.testing import Context, State, CharmSpec class MyCharm(CharmBase): def __init__(self, *args): super().__init__(*args) self.framework.observe(self.on.install, self._on_install) def _on_install(self, event): self.unit.status.set_active() def test_charm(): metadata = yaml.safe_load(''' name: my-charm summary: test series: [focal] ''') spec = CharmSpec(MyCharm, meta=metadata) ctx = Context(spec, meta={'name': 'my-charm'}, actions=None, config=None) state = ctx.run('install', State()) assert state.unit_status.name == 'active' print('Test passed') if __name__ == '__main__': test_charm()
Debug
Known issues
gotchaState-transition tests ('run' with events) require Juju event names as strings (e.g. 'install', 'config-changed', 'update-status'). Using the event type class (e.g. InstallEvent) will fail.
fix
Use string event names: ctx.run('install', State()).
affects: >=3.0.0
breakingIn ops-scenario 8.0.0, the module was renamed from 'scenario' to 'ops.testing'. Old imports from 'scenario' will break.
fix
Replace 'from scenario import ...' with 'from ops.testing import ...'.
affects: 8.0.0+
deprecatedThe 'CharmSpec' constructor argument 'meta' is deprecated; use keyword arguments matching the fields of CharmSpec (like meta, actions, config).
fix
Use explicit keyword args: CharmSpec(MyCharm, meta={...}, actions={...}, config={...}).
affects: >=7.0.0
gotchaWhen using 'ctx.run', the State object is not automatically deep-copied. Mutations to the returned State can affect subsequent runs if the same object is reused.
fix
Always create a fresh State for each run, or use copy.deepcopy if you need to reuse.
affects: >=3.0.0
gotchaThe 'ops' library and 'ops-scenario' must be in sync; using mismatched versions can cause ImportError or AttributeError.
fix
Ensure both come from the same release: pip install 'ops[testing]' handles this automatically.
affects: >=3.0.0
Errors
Common errors & fixes
ImportError: cannot import name 'Context' from 'ops.testing'
ops-scenario not installed or incompatible version; Context moved to ops.testing in v8.
fix
Install with 'pip install ops[testing]' and use 'from ops.testing import Context'.
AttributeError: module 'ops.testing' has no attribute 'State'
Using an older version (pre-3.0) where State was named ScenarioState or not available.
fix
Upgrade to latest ops: 'pip install --upgrade ops[testing]'.
pytest.fixture() got an unexpected keyword argument 'scope'
Incorrectly using a fixture decorator with arguments unsupported by pytest (e.g., from ops.testing.fixture).
fix
Use the standard pytest fixture decorator: @pytest.fixture, not ops.testing.fixture.
TypeError: __init__() got an unexpected keyword argument 'meta'
CharmSpec constructor changed; 'meta' is no longer a keyword argument (use positional or other keys).
fix
Use CharmSpec(MyCharm, meta={...}) is correct; if error persists, check version >=7.0 and use: CharmSpec(MyCharm, meta={...}) still works. This error may be from mixing versions.
Upgrade
Version history
8.7.1latest on PyPI · released May 28, 2026
Audit
Dependencies
opsrequiredCore ops library; ops-scenario is part of the same project.
pyyamloptionalUsed for YAML handling in charm metadata and actions.
pytestoptionalRecommended test runner; not strictly required but commonly used.
Agent activity
4 hits · last 30 days
node
4
Resources
ops-scenario — pip install ops-scenario · libregistry