Pytest Plugin — Enable & Fixtures¶
Enabling the pybuggy plugin gives a test suite the api fixture, the plugin CLI options,
and automatic loading of the generated endpoint fixtures under api/.
Enable the plugin¶
Call goga_tool_pybuggy.plugin.install() from the root conftest.py:
# conftest.py
from dotenv import load_dotenv
load_dotenv()
from goga_tool_pybuggy import plugin
plugin.install()
load_dotenv() runs before install() so plugin options (resolved from os.environ)
see the .env values; the argumentless call keeps override=False (CI/operator-exported
variables win).
There is no import-time auto-wiring:
pytest_plugins = ["goga_tool_pybuggy.plugin"]alone does NOT enable the plugin — the explicitinstall()call is required.
goga tool pybuggy init generates this conftest.py for you when it is absent — an
existing file is kept (bare mode: unless you confirm the overwrite) — see
CLI — init.
What enabling wires¶
- CLI options —
--base-url(resolvesbase_url, required; a typed flag overrides the config-file andBASE_URLvalue),--api-timeout(resolvestimeout),--retries(the flaky rerun count),--api-assert-timeout/--api-assert-delay(the assert-polling baseline). The remaining options (headers,assert_field_class,assert_response_class) have no CLI flag — config-file only. See Configuration. base_urltemplate — a Jinja2 template rendered once atpytest_configureagainstos.environ+ the CLI options you actually passed. Placeholders fed from the CLI require registering those options viapytest_addoptioninconftest.py.- Flaky reruns — when
retriesresolves to a positive int, every collected test without an existing flaky marker is stamped withpytest.mark.flaky(max_runs=retries). The reruns take effect when theflakypackage is installed in the consumer suite; a programmatic default can be passed asinstall(default_retries=N). - The
apifixture — function-scoped, yields the HTTP client built from the resolved options and closes it after the test. Generated endpoint fixtures depend on it; pytest resolvesapiautomatically — no extra wiring:
@pytest.fixture(scope="function")
def get_orders(api: Api) -> Endpoint:
return Endpoint(api, "/orders", method="GET")
- Recursive generated-fixture loading —
install()defaultsloadersto[PackageLoader("api", required=False)], so every generatedapi/<spec>/<id>/api.pymodule is discovered and loaded through the recursivepytest_pluginslist, out of the box.
Overriding discovery¶
Pass an explicit loaders to install(), or add a loader section to the config to do
it declaratively (details: Loaders):
goga_tool_pybuggy.plugin.install(loaders=[PackageLoader("api"), PackageLoader("service")])
goga_tool_pybuggy.plugin.install(loaders=[]) # disable discovery entirely
# .goga/tools/pybuggy/config.yml
loader:
packages:
- name: api # walk the api/ package tree (dots map to path separators)
required: false # tolerate a missing tree
modules:
- my_plugin.conftest
Preconditions and side effects¶
- The
api/tree is discovered by default; a missing tree is tolerated (required=False). - The plugin reads
.goga/tools/pybuggy/config.ymlat import; a missing file is tolerated (defaults apply). - Loader paths walk the filesystem relative to the current working directory (while
candidate imports go through
sys.path). Runpytestfrom the project root — the directory that both containsapi/and is onsys.path. Running from another directory makes discovery silently return[], so generated fixtures are not loaded and tests fail withfixture '<name>' not found.
Test reruns¶
Two mechanisms exist:
- Suite-wide — the
retriesoption (orinstall(default_retries=N)) stamps every collected test without an existing flaky marker; requires theflakypackage in the suite. - Per-test decorator — the facade
retriesdecorator (from goga_tool_pybuggy import retries; built on theflakypackage):@retries(max_runs=3, min_passes=2, delay=1)reruns a flaky test up tomax_runstimes requiringmin_passessuccesses, pausingdelayseconds between reruns.