tg-auto-test
A serverless testing library for python-telegram-bot applications. Runs a real PTB Application in-process with a fake Bot API transport. Tests use Telethon-like interfaces for assertions.
What it is
tg-auto-test allows you to write fast, reliable tests for your Telegram bots without making network calls to the real Telegram Bot API. It:
- Runs your python-telegram-bot
Applicationin-process with all handlers intact - Provides a fake Bot API transport that captures and responds to API calls
- Offers a
ServerlessTelegramClientthat mimics Telethon's client interface - Bridges outgoing Bot API calls into Telethon TL objects for consistent test assertions
- Supports media files, inline keyboards, payments (Stars), and bot commands
What it is NOT
- Not a Telegram bot framework — use python-telegram-bot for that
- Not a Telethon replacement — it is a fake Telethon, specifically for testing PTB bots
- Not for real Telegram network tests — all communication is simulated in-memory
Design philosophy
tg-auto-test is a fake Telethon. The core idea is to build a drop-in replacement for Telethon's TelegramClient that works entirely in-memory — no internet connection, no Telegram account, no API tokens, no authentication.
Any code that accepts a Telethon client should also accept our ServerlessTelegramClient and get the same behavior. This includes the Demo UI bundled with this library: it works identically whether you pass a real TelegramClient or our fake one.
Key principles:
-
We re-implement, not invent. Our fake classes (
ServerlessTelegramClient,ServerlessMessage,ServerlessTelegramConversation,ServerlessButton) mirror real Telethon public interfaces exactly — same method names, parameter names, positional/keyword-only markers, defaults, and types. We do not add custom public methods. -
Conformance tests enforce parity. Forward conformance tests verify our fakes have no extra public methods beyond Telethon. Reverse conformance tests verify every Telethon public method exists on our fakes. Signature conformance tests verify parameter-level match using
inspect.signature(). Seetests/unit/test_telethon_conformance_*.pyandtests/unit/test_telethon_reverse_conformance_*.py. -
Unimplemented methods fail loudly. Any Telethon public method we haven't implemented raises
NotImplementedError— never a silent no-op, never anAttributeError. -
_-prefixed internals are the exception. Internal test infrastructure methods (like_pop_response,_api_calls) are prefixed with_and are not part of the Telethon interface contract. -
Single chat only. The library simulates one private chat between a user and a bot. No multi-user, no group chats, no channels. This is a deliberate scope constraint.
How it works
You provide a build_application callback that configures your PTB Application with handlers. The library provides a ServerlessTelegramClient that implements Telethon's client interface, bridging outgoing Bot API calls into Telethon TL objects for assertions.
Quickstart
from telegram.ext import Application, ApplicationBuilder, CommandHandler, ContextTypes, MessageHandler, filters
from telegram import Update
from tg_auto_test.test_utils.serverless_telegram_client import ServerlessTelegramClient, TelegramApiCall
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.message.reply_text(update.message.text)
def build_app(builder: ApplicationBuilder) -> Application:
app = builder.build()
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
return app
# In your test:
client = ServerlessTelegramClient(build_application=build_app)
await client.connect()
async with client.conversation("test_bot") as conv:
await conv.send_message("hello")
msg = await conv.get_response()
assert msg.text == "hello"
await client.disconnect()
Public API
ServerlessTelegramClient
Main entry point for serverless testing:
ServerlessTelegramClient(
build_application: Callable[[ApplicationBuilder], Application],
user_id: int = 9001,
first_name: str = "Alice",
bot_username: str = "test_bot",
bot_first_name: str = "TestBot"
)
Conversation management:
conversation(entity, *, timeout=60.0)— create conversation context manager
ServerlessTelegramConversation
Async context manager for message exchange:
await conv.send_message(text, *, parse_mode=(), formatting_entities=None)— send text messageawait conv.send_file(file, *, caption="", parse_mode=(), formatting_entities=None, force_document=False, voice_note=False, video_note=False)— send fileawait conv.get_response() -> ServerlessMessage— get bot's response
Client and conversation text/file sends accept Telethon Markdown (md/markdown),
HTML, or explicit Telethon formatting entities. The default parse mode is Markdown;
parse_mode=None disables parsing. Explicit entities take precedence over parsing.
Incoming PTB messages receive visible text and Bot API entities or
caption_entities separately, including hidden link URLs and UTF-16 offsets.
ServerlessMessage
Response object with Telethon-compatible interface:
.text: str— message text.photo: Photo | None— photo media.document: Document | None— document media (excludes voice/video notes).voice: Document | None— voice note media.video_note: Document | None— video note media.file: TelethonFile | None— Telethon File wrapper with.size,.width,.height,.mime_type,.name.invoice: MessageMediaInvoice | None— invoice details.buttons: list[list[ServerlessButton]] | None— keyboard button rows.button_count: int— total number of buttonsawait .download_media(file=bytes) -> bytes | None— download media bytesawait .click(data: bytes) -> ServerlessMessage— click inline button
TelegramApiCall
Data class representing a single Bot API call:
.api_method: str— the API method name (e.g., "sendMessage", "getMe").parameters: dict[str, str]— request parameters sent to the API.file: FileData | None— uploaded file data, if any.result: JsonValue | None— the API response result, if successful
Supported Telethon RPC subset
GetBotCommandsRequest— retrieve bot commandsGetBotMenuButtonRequest— retrieve chat menu buttonGetStarsStatusRequest— get Stars balanceGetPaymentFormRequest— get payment form for Stars invoiceSendStarsFormRequest— submit Stars paymentSendVoteRequest— vote in a poll
Supported Bot API methods
Core messaging:
sendMessage— send text messages with reply markupeditMessageText— edit message text
Media:
sendDocument— send documentssendVoice— send voice notessendPhoto— send photossendVideoNote— send video notes
Payments:
sendInvoice— send Stars payment requestsanswerPreCheckoutQuery— approve/reject payment
Polls:
sendPoll— send polls with multiple options
Interactive:
answerCallbackQuery— respond to inline button presses
Bot configuration:
setMyCommands,getMyCommands,deleteMyCommands— manage bot commandssetChatMenuButton,getChatMenuButton— manage chat menu button
Actions & lifecycle:
sendChatAction— send chat action (typing, uploading, etc.)deleteMessage— delete a message
Utilities:
getMe— get bot informationgetFile— get file information
Limitations & extension seams
Current limitations:
- PTB-only bridge (architecture allows adding aiogram, raw HTTP adapters)
- Unsupported Bot API methods raise
AssertionError(fail-fast design) - Single private chat only — no multi-user, group chats, or channels
- No reactions or albums
- No support for
sendVideo,sendAudio,sendAnimation,sendLocation,sendSticker
Extension points:
The architecture is designed to support additional frameworks and features. See TODO.md for planned extensions.
Dependencies & licenses
Runtime dependencies:
python-telegram-bot(LGPL-3.0) — Users should be aware of LGPL implications for their projectsTelethon(MIT)Pillow(HPND, permissive)
Development dependencies:
pytest,pytest-asyncio,pytest-xdist— testingruff,pylint,vulture— code qualitybuild,twine— packaging
Contributing
Prerequisites:
- Python 3.12+
uvpackage manager- Node.js (for jscpd duplicate detection)
Setup:
uv sync --dev
Quality gates:
All Python execution must go through uv. Run make check before submitting PRs — it must pass 100%.
Code style:
- Enforced by ruff configuration
- 200-line module limit (enforced by linter)
- No
.envfiles — this project uses Doppler for secrets management
See CONTRIBUTING.md for detailed guidelines.
Demo UI
tg-auto-test includes a local web UI for interactive bot testing. The Demo UI accepts any Telethon-compatible client — both the real TelegramClient and our ServerlessTelegramClient work through the same standard Telethon interfaces. This is a practical proof that our fake client is a true drop-in replacement.
What it is
The Demo UI is a local web server that provides:
- Browser-based chat interface for testing bots
- Support for text messages, media files (photos, documents, voice notes, video notes)
- Inline keyboard interaction (button clicking)
- Poll voting
- Stars payment simulation
- Bot state inspection (commands, menu buttons)
Security
⚠️ SECURITY WARNING: The Demo UI is intended for localhost development only. Never expose it to public networks or production environments. It runs without authentication and could expose sensitive bot functionality.
Installation
Install with the demo extra to get FastAPI and web server dependencies:
pip install tg-auto-test[demo]
Quickstart: Serverless Mode
Use with ServerlessTelegramClient for fast, in-memory bot testing:
from tg_auto_test.test_utils.serverless_telegram_client import ServerlessTelegramClient
from tg_auto_test.demo_ui.server.demo_server import create_demo_app
import uvicorn
def build_app(builder):
# Your PTB Application setup here
app = builder.build()
# Add handlers...
return app
# Create serverless client
client = ServerlessTelegramClient(build_application=build_app)
# Create demo app
demo_app = create_demo_app(client=client, peer="test_bot")
# Run server
uvicorn.run(demo_app, host="127.0.0.1", port=8000)
Navigate to http://127.0.0.1:8000 to interact with your bot.
Quickstart: Telethon Mode
Use with a real Telethon client for testing with authenticated sessions:
from telethon import TelegramClient
from tg_auto_test.demo_ui.server.demo_server import create_demo_app
import uvicorn
# Create authenticated Telethon client
client = TelegramClient('session_name', api_id, api_hash)
# Create demo app
demo_app = create_demo_app(client=client, peer="@your_bot_username")
# Run server (client lifecycle managed automatically)
uvicorn.run(demo_app, host="127.0.0.1", port=8000)
Supported features
- Text messages
- Media files (photos, documents, voice notes, video notes)
- Inline keyboards (button clicking and callback handling)
- Polls (creation and voting)
- Stars payments (invoice creation and payment simulation)
- Bot commands and menu button inspection
Not yet supported: message edit tracking, multi-chat, albums.
Metadata
Release files for tg-auto-test 1.3.23
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tg_auto_test-1.3.23.tar.gz | 76.6 kB | Without provenance | Details for tg_auto_test-1.3.23.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tg_auto_test-1.3.23-py3-none-any.whl | Python 3 | none | any | Details for tg_auto_test-1.3.23-py3-none-any.whl |
Total release size: 178.0 kB
Release files / tg_auto_test-1.3.23.tar.gz
| Download URL | tg_auto_test-1.3.23.tar.gz |
|---|---|
| Size | 76.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e854545c4be824a341069031608a0cb7edb4381b0ac06c02812343b52b790b28
|
|
BLAKE2b-256 checksum How to use checksums |
828f2aaec8ca5280832b0ab7aac8abfda48952529f2bf600a4db50adf4a911a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.14
|
Release files / tg_auto_test-1.3.23-py3-none-any.whl
| Download URL | tg_auto_test-1.3.23-py3-none-any.whl |
|---|---|
| Size | 101.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
de883acf6332c8c43c44b2af113312981b1b7e1e687a1ad4565bfb9ac7231ac1
|
|
BLAKE2b-256 checksum How to use checksums |
a6d81ee354706087b352d0b0f0f511dd8d4950642df7e83d7d1f88d2bfc58524
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.14
|
Security for tg-auto-test 1.3.23
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.