Test chat bots, voice assistants, and IVR menus with pytest using a small Conversation object and a callable bot adapter. Use when the user wants to write rule-based assertions over multi-turn dialogue without bringing in an LLM dependency, when they have a chatbot reachable as a Python callable or HTTP webhook, when they need to keep per-conversation state across turns and assert on slot filling, when they want pytest-native fixtures and a printable transcript on failure, or when they mention voice-assistant testing, IVR menu testing, conversational AI testing, LLM bot testing (used as the target under test, not as the matcher), expect matchers for bot replies, or multi-turn dialogue tests.
99
100%
Does it follow best practices?
Impact
97%
1.56xAverage score across 3 eval scenarios
Passed
No known issues
All notable changes to pytest-conversational are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
load_scenarios now rejects a file that defines two scenarios with the same
name, raising ScenarioLoadError instead of loading them. Names are used as
pytest parametrize ids, so duplicates previously caused pytest to mangle the
ids silently and broke -k name targeting. A file that relied on duplicate
names (unlikely, since they were already broken) must give each scenario a
unique name.First stable release. The public API (the conversation fixture, the
expect matchers, scenario loading, and the bot adapter protocol) is now
considered stable and follows semantic versioning from here.
expect.not_contains matcher: the negative of contains, asserting a
substring is absent from a reply. Useful for leak guards (bot must not echo
an internal error, a stack trace, or a value it was never given).
Case-insensitive by default; raises on a None reply.allure_attach_transcript
fixture serializes the Conversation as transcript.json (turns, state,
metadata) and transcript.md (rendered turn-by-turn), then attaches both
to the Allure report when the test fails. Optional --conversational-always-attach
CLI flag also attaches on passing runs. The fixture is graceful: if
allure-pytest is not installed the attach is a no-op, so the feature
carries no hard dependency. New allure extra in pyproject.toml pulls
allure-pytest>=2.13 when users opt in.expect matchers: slot, state, intent, and latency for testing
structured conversation outputs (state machine slots, intent labels, response
timing budgets).allowed_hosts parameter: pin tests to a host
allowlist with case-insensitive comparison, trailing-dot normalisation, and
scheme check. URLs outside the allowlist raise ValueError before the
request goes out.max_reply_bytes, default 1 MiB):
bound the response body size before parsing to fail fast on runaway
adapters.one_of: contributor PR #5 by
SHIVANSH-ux-ys.SKILL.md and REFERENCE.md for Tessl Registry submission (review score
100%).conversational pytest marker registration.__init__.py is now read from package metadata via
importlib.metadata.version, removing the second source of truth.say documents partial-turn semantics: the Turn is appended to history
before the adapter call, so adapter exceptions still leave a traceable
transcript.SKILL.md contains the quick-start surface,
REFERENCE.md holds the public API, matchers reference, and CI templates.allowed_hosts
and surfaces a clear ValueError instead of issuing the request.expect matchers: contains, regex, and one_of, each with a case_sensitive keyword.pytest_conversational.adapters.http_webhook) for testing chat backends over HTTP.BotAdapter) with state preserved across turns.Conversation and Turn primitives that drive multi-turn flows from pytest tests.pyproject.toml, CI matrix on Python 3.10 / 3.11 / 3.12, smoke tests..tessl-plugin
evals
src
pytest_conversational
tests