Python library providing a state-transition testing API for Operator Framework charms.
Project description
ops-scenario, the unit testing framework for ops charms
ops-scenario is a Python library that provides state-transition testing for
Ops charms. These tests are higher level than
typical unit tests, but run at similar speeds and are the recommended approach
for testing charms within requiring a full Juju installation.
Test are written in the arrange/act/assert pattern, arranging an object representing the current Juju state, acting by emulating an event from Juju, and then asserting on the (simulated) output Juju state.
Writing tests
Here's a test that verifies that a unit is active after the start event, with a very minimal initial state:
from ops import testing
# 'src/charm.py' typically contains the charm class.
from charm import MyCharm
def test_start():
ctx = testing.Context(MyCharm)
state_in = testing.State()
state_out = ctx.run(ctx.on.start(), state_in)
assert state_out.unit_status == testing.ActiveStatus()
More comprehensive tests will include relations, containers, secrets, and other components in the input state, and assertions against both the output state and the context. The 'act' stage remains a simple single call, although additional arguments may be required for the event, such as the relation or container that triggered it. For example:
import pytest
from ops import testing
from charm import MyCharm
@pytest.mark.parametrize(
'leader',
[pytest.param(True, id='leader'), pytest.param(False, id='non-leader')],
)
def test_(leader: bool):
# Arrange:
ctx = testing.Context(MyCharm)
relation = testing.Relation('db', local_app_data={'hostname': 'example.com'})
peer_relation = testing.PeerRelation('peer')
container = testing.Container('workload', can_connect=True)
relation_secret = testing.Secret({'certificate': 'xxxxxxxx'})
user_secret = testing.Secret({'username': 'admin', 'password': 'xxxxxxxx'})
config = {'port': 8443, 'admin-credentials': 'secret:1234'}
state_in = testing.State(
leader=leader,
config=config,
relations={relation, peer_relation},
containers={container},
secrets={relation_secret, user_secret},
unit_status=testing.BlockedStatus(),
workload_version='1.0.1',
)
# Act:
state_out = ctx.run(ctx.on.relation_changed(relation), state_in)
# Assert:
assert testing.JujuLogLine(level='INFO', message='Distributing secret.') in ctx.juju_log
peer_relation_out = state_out.get_relation(peer_relation.id)
assert peer_relation_out.peers_data[0] == {'secret_id': relation_secret.id}
You don't have to use pytest for your charm tests, but it's what we recommend.
pytest's assert-based approach is a straightforward way to write tests, and
its fixtures are helpful for structuring setup and teardown.
Installation
For charm tests, install the testing framework by adding the testing extra of
ops in your unit testing environment. For example, in pyproject.toml:
[dependency-groups]
test = ['ops[testing]<4.0']
Ops checks if ops-scenario is installed, and, if so, makes the classes
(such as Context, State, and Relation) available in the ops.testing
namespace. Use from ops import testing rather than importing the scenario
package.
ops-scenario supports the same platforms and Python versions as ops itself.
Documentation
- To get started, work through our 'Write your first Kubernetes charm' tutorial, following the instructions for adding unit tests at the end of each chapter.
- When you need to write a test that involves specific ops functionality, refer to our how-to guides which all conclude with examples of tests of the ops functionality.
- Use our extensive reference documentation when you need to know how each
testingobject works. These docs are also available via the standard Pythonhelp()functionality and in your IDE.
Community
ops-scenario is a member of the Charming family. It's an open source project
that warmly welcomes community contributions, suggestions, fixes and
constructive feedback.
- Read our code of conduct: As a community we adhere to the Ubuntu code of conduct.
- Get support: Discourse is the go-to forum for all Ops-related discussions, including around testing.
- Join our online chat: Meet us in the #charmhub-charmdev channel on Matrix.
- Report bugs: We want to know about the problems so we can fix them.
- Contribute docs: Get started on GitHub.
Contributing and developing
Anyone can contribute to ops and ops-scenario. It's best to start by
opening an issue with a clear
description of the problem or feature request, but you can also
open a pull request directly.
Read our guide for more details on how to work on and
contribute to ops-scenario.
Currently, releases of ops-scenario are done in lockstep with releases of ops
itself, with matching minor and bugfix release numbers. The ops documentation
outlines how to create a new release.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ops_scenario-8.5.2.tar.gz.
File metadata
- Download URL: ops_scenario-8.5.2.tar.gz
- Upload date:
- Size: 71.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ebcdc4f8837f9a1cd42624f49d9d8b2502ebeeedad552516225b3420f989c369
|
|
| MD5 |
3dd406fa1abf0aa4d754f3c39214b98c
|
|
| BLAKE2b-256 |
cb27a999aa877a34fc1b2c07b0f51cb1dc58a89e23bcaf4f626e28bec39825fd
|
Provenance
The following attestation bundles were made for ops_scenario-8.5.2.tar.gz:
Publisher:
publish.yaml on canonical/operator
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ops_scenario-8.5.2.tar.gz -
Subject digest:
ebcdc4f8837f9a1cd42624f49d9d8b2502ebeeedad552516225b3420f989c369 - Sigstore transparency entry: 939067114
- Sigstore integration time:
-
Permalink:
canonical/operator@a958024e2b25a176a86083fc467e2b0c8fea81fa -
Branch / Tag:
refs/tags/3.5.2 - Owner: https://github.com/canonical
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@a958024e2b25a176a86083fc467e2b0c8fea81fa -
Trigger Event:
push
-
Statement type:
File details
Details for the file ops_scenario-8.5.2-py3-none-any.whl.
File metadata
- Download URL: ops_scenario-8.5.2-py3-none-any.whl
- Upload date:
- Size: 64.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79125d82ca753394d9d9e4a53c55931d3d0114421c1b745f5611cb5827d37012
|
|
| MD5 |
3b01bee08b563b0648d429157cfab537
|
|
| BLAKE2b-256 |
3ab157816b48087fa391d0b113e067ca80fdd36a2103c57cf9cf28fe5a82f52e
|
Provenance
The following attestation bundles were made for ops_scenario-8.5.2-py3-none-any.whl:
Publisher:
publish.yaml on canonical/operator
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ops_scenario-8.5.2-py3-none-any.whl -
Subject digest:
79125d82ca753394d9d9e4a53c55931d3d0114421c1b745f5611cb5827d37012 - Sigstore transparency entry: 939067163
- Sigstore integration time:
-
Permalink:
canonical/operator@a958024e2b25a176a86083fc467e2b0c8fea81fa -
Branch / Tag:
refs/tags/3.5.2 - Owner: https://github.com/canonical
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@a958024e2b25a176a86083fc467e2b0c8fea81fa -
Trigger Event:
push
-
Statement type: