Migrates legacy ops.testing Harness suites to state-transition tests by enumerating Harness usages, defining explicit State objects, and recreating assertions per Juju event so charms stay compatible with modern ops releases.
67
80%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/migrate-harness-tests-to-state-transition-test/SKILL.mdGuide charm maintainers through replacing deprecated Harness-based unit tests with deterministic state-transition tests that mirror how Juju actually fires events. Use this skill whenever a test still instantiates testing.Harness or chains multiple events inside one fixture.
ops.testing.Harness (or Scenario Harness helpers) still appear in tests or fixtures.testing.State.add_relation, evaluate_status, etc.) are removed.pyproject.toml (or requirements files) before touching code; ensure ops[testing] is present in every dependency group that executes Scenario/state-transition tests. Remove legacy ops-scenario if it lingers.uv add --group unit ops[testing] (and mirror across groups) when [tool.uv] or uv.lock exists; otherwise edit the appropriate requirements.txt, Poetry group, etc.uv sync --group unit --group lint, poetry install, etc.) so the virtualenv contains Scenario Context.uv sync, pip install -r requirements.txt, make setup, …) to align local + CI execution before rewriting tests.Create a written task list before editing files and keep it updated:
tox.toml wires environments to uv runners; it keeps CI parity.ops[testing] is added to one group, mirror it across any environment that imports Scenario helpers.Makefile/tox.toml before running bespoke setup commands—they often wrap the correct bootstrap flow.PenpotStateBuilder, create_state) and port their internals to Scenario primitives when available.State objects only when Harness usage was minimal; large charms benefit from shared factories so relations/secrets stay consistent.scripts/find_harness_tests.py against tests/ and categorize hits by surface area (actions, relations, Pebble, status).testing.State with relations, containers, config, leadership, secrets, and network data—Scenario never replays incremental Harness mutations.ctx.run(ctx.on.<event>(...), state_in) and assert on state_out, ctx.action_results, emitted statuses, and monkeypatched workload helpers.pytest.raises(testing.ActionFailed) or other exception checks; add separate tests for each branch instead of branching inside one function.tox -e unit -- tests/unit/test_charm.py) right after editing each file; log the result in the ledger.tox -e unit, pytest tests/unit) and only mark the migration complete when it returns 0 with zero Harness matches.scripts/find_harness_tests.py: Recursively scans the provided paths for testing.Harness/Scenario references. Usage:
python3 .github/skills/migrate-harness-tests-to-state-transition-test/scripts/find_harness_tests.py tests/unit tests/integrationreferences/migration-checklist.md: Step-by-step plan that maps every Harness helper to its state-transition counterpart and reminds you to satisfy collect-status requirements.references/state-transition-recipes.md: Ready-to-paste snippets for actions, relation-changed, Pebble-ready, update-status, and failure cases.ctx.on.action("name", params=...); assert on ctx.action_results and expected failures (testing.ActionFailed). Provide container data when _on_collect_status inspects Pebble.testing.Relation instance in both State and ctx.on.relation_changed(...); populate remote/local databags with the "new" data that triggered the event.testing.Container objects with realistic layers, service_statuses, and can_connect flags. Inspect the output container via state_out.get_container(name).ctx.on.update_status() to cover _on_collect_status; create success and failure variants (inactive service, disconnected container, missing plan).testing.Harness so I can migrate them to state-transition tests."tests/unit/test_charm.py::test_relation_changed using the relation recipe and show the new testing.State."_on_collect_status stops failing inside the new tests."scripts/find_harness_tests.py with zero hits.tox -e unit (or repo equivalent) succeeds after dependency sync and Harness removal.d41d8d9
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.