{"id":10145,"library":"pytest-operator","title":"pytest-operator","description":"pytest-operator provides a set of pytest fixtures designed to simplify the testing of Charmed Operators, particularly for integration and functional tests. It abstracts away much of the complexity of deploying and managing Juju models and charms within a test environment. The current version is 0.43.2, and it maintains an active release cadence with frequent patch updates and occasional minor feature releases.","status":"active","version":"0.43.2","language":"en","source_language":"en","source_url":"https://github.com/charmed-kubernetes/pytest-operator","tags":["pytest","testing","operators","juju","charmed-kubernetes","devops"],"install":[{"cmd":"pip install pytest-operator","lang":"bash","label":"Install pytest-operator"}],"dependencies":[{"reason":"pytest-operator is a plugin for pytest.","package":"pytest","optional":false},{"reason":"Used for building charm bundles within test environments. Required for ops_test.build_charm().","package":"charmcraft","optional":true}],"imports":[{"note":"pytest plugins are loaded via the `pytest_plugins` variable in a `conftest.py` or test module, not direct import.","wrong":"from pytest_operator import plugin","symbol":"pytest_plugins","correct":"pytest_plugins = ['pytest_operator.plugin']"}],"quickstart":{"code":"# conftest.py\npytest_plugins = [\"pytest_operator.plugin\"]\n\n# tests/integration/test_my_charm.py\nimport pytest\nfrom pathlib import Path\n\n# Assuming your charm source is in a 'src' directory relative to the tests\nCHARM_ROOT = Path(__file__).parent.parent / \"src\"\n\nasync def test_charm_is_deployed(ops_test):\n    # Build the charm locally\n    charm = await ops_test.build_charm(CHARM_ROOT)\n    \n    # Deploy the charm to the ephemeral Juju model\n    await ops_test.model.deploy(charm)\n    \n    # Wait for the application to reach an idle state\n    await ops_test.model.wait_for_idle(apps=[charm.name], status=\"active\", timeout=600)\n    \n    # Assertions about the application state\n    assert ops_test.model.applications[charm.name].units[0].workload_status == \"active\"","lang":"python","description":"This quickstart demonstrates a basic integration test using `pytest-operator`. It shows how to declare the plugin in `conftest.py`, build a charm using `ops_test.build_charm()`, deploy it to a temporary Juju model, and assert its status. Ensure `charmcraft` is installed if you are building charms locally."},"warnings":[{"fix":"Be aware that external Juju models are not affected. If you need to debug a model, you can set `PYTEST_OPERATOR_KEEP_MODEL=true` in your environment, but manual cleanup will be required.","message":"The `ops_test` fixture operates on a clean, ephemeral Juju model for each test session. Any deployments or changes made during a test run are automatically cleaned up afterward, meaning no persistent state between test runs.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Install charmcraft: `snap install charmcraft --classic` or ensure it's in your virtual environment if using a tool like `pipx`.","message":"To use `ops_test.build_charm()`, `charmcraft` must be installed and accessible in your system's PATH. If `charmcraft` is not found, charm building will fail.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Design tests to be as efficient as possible. Leverage shared fixtures (e.g., a single deployment for multiple tests in a module if safe) and consider using `pytest-xdist` for parallel execution, if applicable, for larger test suites.","message":"Integration tests can be significantly slower than unit tests due to the overhead of building charms, deploying applications, and waiting for Juju model states.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Ensure `pytest-operator` is installed (`pip install pytest-operator`). In your `conftest.py` (or the test module itself), add `pytest_plugins = ['pytest_operator.plugin']`.","cause":"The `pytest-operator` plugin is not correctly loaded by pytest. This usually happens if `pytest-operator` is not installed, or if the `pytest_plugins` declaration is missing or incorrect in `conftest.py`.","error":"fixture 'ops_test' not found"},{"fix":"Install `charmcraft` via `snap`: `sudo snap install charmcraft --classic`. Avoid `pip install charmcraft` as it's not the officially supported installation method for the CLI tool.","cause":"This error often indicates an issue with the `charmcraft` installation or its compatibility with the Python environment, particularly if `charmcraft` was installed via `pip` instead of `snap`.","error":"ModuleNotFoundError: No module named 'charmcraft.juju.local'"},{"fix":"Verify `charmcraft` is installed and its binary is in your system's PATH. If installed via snap, ensure snap binaries are in PATH (e.g., `export PATH=$PATH:/snap/bin`).","cause":"The `charmcraft` executable is not found in the system's PATH, even if it might be installed.","error":"FileNotFoundError: [Errno 2] No such file or directory: 'charmcraft'"},{"fix":"Check the charm's build log in the test output. Verify the `CHARM_ROOT` path is correct. Review Juju agent logs (`juju debug-log`) to pinpoint the issue. Ensure your test environment has necessary resources (e.g., sufficient disk space).","cause":"The charm deployment failed. This could be due to issues within the charm's code, incorrect charm path provided to `build_charm`, or problems with the underlying Juju environment setup by `pytest-operator`.","error":"AssertionError: Expected 1 application to be deployed, but found 0 (or similar deployment failure)"}]}