Skip to main content

Black-box testing for aiogram 3.x Telegram bots - no network, no token

Project description

teremok

PyPI Python CI

Black-box testing for aiogram 3.x Telegram bots. No network, no token, no mock servers - each test runs in milliseconds.

Inspired by Rust's teremock: send mock updates through your real dispatcher, then assert on what the bot sent back. Named after the folk tale about a little house whose guests arrive one by one - just like updates entering your bot.

Install

pip install teremok

Test setup

pip install teremok pytest-asyncio

teremok's tests (and the mock_bot fixture) are async def. Without pytest-asyncio configured, async tests fail to run - add this to your pyproject.toml (or the equivalent in pytest.ini):

[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"

The quickstart below depends on this setting.

Quickstart

from aiogram import Router
from aiogram.filters import Command
from aiogram.types import Message

from teremok import MockBot, MockMessageText

router = Router()

@router.message(Command("start"))
async def cmd_start(message: Message) -> None:
    await message.answer("Hello!")

async def test_start(mock_bot):          # `mock_bot` fixture ships with the package
    bot = mock_bot(router)
    result = await bot.dispatch(MockMessageText("/start"))
    assert result.handled
    assert bot.requests.send_message[0].text == "Hello!"

Captures are typed aiogram objects, not JSON: bot.requests.send_message returns SendMessage instances, bot.requests.send_photo[0].photo is the actual InputFile your handler passed.

FSM and multi-step conversations

bot = mock_bot(form_router)
await bot.dispatch(MockMessageText("/form"))
await bot.dispatch(MockMessageText("Alice"))
await bot.dispatch(MockMessageText("30"))
assert bot.requests.send_message[-1].text == "Nice to meet you, Alice (30)!"
assert await bot.get_state() is None

# Or jump straight into the middle of a flow:
await bot.set_state(Form.age)
await bot.set_data({"name": "Bob"})

Files and media

bot.add_file("photo_1", b"...jpeg bytes...")     # bot.download() returns this
await bot.dispatch(MockMessagePhoto(file_id="photo_1", caption="lunch"))
assert bot.requests.send_photo[0].photo.filename == "echo.jpg"

Custom API results and errors

from aiogram.methods import SendMessage

bot.add_result(SendMessage, ok=False, error_code=400,
               description="Bad Request: chat not found")
# strict mode: MockBot(router, strict=True) fails on any un-queued call

Results are keyed by method type: queuing a SendMessage result never answers an AnswerCallbackQuery (or any other method) call that happens to run first - every other call keeps auto-responding.

What's covered

Every Bot API method is captured (interception happens below all methods, at aiogram's session seam). Auto-response fidelity per method is tracked honestly in docs/coverage.md; known edge cases live in docs/quirks.md. Runnable examples: examples/.

CI's freshness gate regenerates that table against the latest aiogram release on every run, so a new aiogram release can turn CI red until someone regenerates and commits the table - that's expected behavior, not a teremok bug.

Releasing (maintainers)

Tag vX.Y.Z and push - GitHub Actions builds and publishes via PyPI Trusted Publishing (configure once in PyPI project settings).

Credits

The name and the whole idea are borrowed with love from teremock by @zerosixty — a Rust testing library for teloxide bots (MIT). teremok is its independent aiogram counterpart: no code is shared (different language, different framework), but the black-box testing philosophy — and the pun — are theirs. Related prior art: teloxide_tests.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

teremok-0.1.0.tar.gz (41.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

teremok-0.1.0-py3-none-any.whl (11.9 kB view details)

Uploaded Python 3

File details

Details for the file teremok-0.1.0.tar.gz.

File metadata

  • Download URL: teremok-0.1.0.tar.gz
  • Upload date:
  • Size: 41.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for teremok-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e68fa9c85c1deeba4b0a8e9aba3124f1d8288387e05620cf8acf64faea80c94b
MD5 1f57253eaa14b3ed5af134044f7cfdc9
BLAKE2b-256 c36d2f638e3eff1810b4be70e7ce3115d3b950fd160d6a890c161e2a245997ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for teremok-0.1.0.tar.gz:

Publisher: publish.yml on 0x216/teremok-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file teremok-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: teremok-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for teremok-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9879869da9b463c39dc6f619864b3453819087d739df7a14ba30b75e3d537238
MD5 51ea4924bf4c95c9d350e484966b4157
BLAKE2b-256 ad2e92ffe6eea07d41bd0f9ab2c3f292066df76863111e72ae24e4ce3a842000

See more details on using hashes here.

Provenance

The following attestation bundles were made for teremok-0.1.0-py3-none-any.whl:

Publisher: publish.yml on 0x216/teremok-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page