Как сделать тест в Телеграмм боте

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Switch branches/tags
Branches Tags
Could not load branches
Nothing to show
Could not load tags

Nothing to show

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Cancel Create

  • Local
  • Codespaces

HTTPS GitHub CLI
Use Git or checkout with SVN using the web URL.
Work fast with our official CLI. Learn more about the CLI.

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Как сделать тестирование в чат-боте

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

Latest commit message
Commit time

README.md

Quiz Telegram Bot

  • Вопросы представить вопросы по категориям: javascript, angular, jest, vue, webpack, enzyme, typescript, flow
  • Вопросов должно быть создано с запасом, чтобы была некая рандомность
  • Пользователь должен ответить на Nx вопросов по каждой категории
  • Кол-во Nx определяется по каждой категории в отдельности. И записывается во время миграции вопросов.
  • При получении ответа от Игрока сразу высчитываем «правильность» и сохраняем в БД
  • В Игроке нужно хранить статус «в очереди на отправку» или «ожидает новый вопрос» чтобы проще было фильтровать пользователей, которые ждут вопрос
  • В каждом пользователе нужно хранить дату смены статуса, чтобы по ней делать выборку. Так можно спамить не более Y раз в Z минут. И находить пользователей, сообщения которых висят в очереди.
  • Пока пользователь не ответит, не присылать ему новый вопрос
  • Есть некий дедлайн, после которого не высылаются вопросы игроку
  • Нельзя завершить тест в любой момент. Тест считается завершенным, когда получены ответы на все вопросы
  • Один и тот же игрок может играть оба дня. И при этом его статистика должна делиться
  • HR определяют победителя по статистике ответов по каждому игроку
  • Никаких шуток в боте
  • Стараемся делать вопросы с ответами в виде кнопок, радиобатонов, чекбоксов
  • Вопросы идут один за одним

Статусная модель пользователя

new -> waiting-questions -> with-question -> end

Каждый экшен должен возврщать промис с объектом типа

< message: < id, // id чата msg, // текст сообщения (вопроса) replies // массив возможных ответов (кнопки) >gamer: , >

Опросники по javascript

Как создать тесты онлайн: делаем тест «Какой ты…» через чат-бота

  • https://www.javatpoint.com/javascript-quiz
  • http://davidshariff.com/js-quiz/
  • https://learn.javascript.ru/quiz
  • http://perfectionkills.com/javascript-quiz/
  • https://www.w3schools.com/quiztest/quiztest.asp?qtest=JavaScript

// Установка монги docker pull mongo // Старт монги docker run -d -p 27017:27017 -v ~/mongo_data:/data/db mongo
// Установка редиса docker pull redis // Старт редиса docker run -d -p 6379:6379 redis

  • Создать файл config/development.json
  • Скопировать из config/default.json те атрибуты, которые нужно переопределить. И заполнить их значениями

Для миграции в составе репозитория присутствует мигратор. Для запуска необходим файл js с вопросами в формате

Далее в терминале выполнить npm run migrator — -f path-to-questionnaires.js . Чтобы удалить существующие вопросы, нужно выполнить с флагом —force , например: npm run migrator — —force -f path-to-questionnaires.js . Для вывода всех возможных свойств мигратора выполнить npm run migrator — —help

Чтобы запустить приложение с development.json конфигом, нужно выполнить npm start или npm run bot:development . Для запуска api-сервера статистики необходимо выполнить npm run api:development .

Для продакшн режима созданы похожие команды npm run bot:production и npm run api:production .

Чтобы стартовало приложение в режиме с испольхованием webhook необходимо локально:

  1. Скачать утилиту https://ngrok.com/download — это локальный ssl туннель Зарегистрироваться, прописать authtoken, стартовать ngrok Из полученного при старте вывода скопировать ссылку вида

https://d39febbf.ngrok.io

  1. В локальном файле конфигурации в папке сщташп (development.js, prealpha.js, production.js, default.js — любом, какой есть) прописать в поле url полученную ссылку
  2. Стартовать бота
Еще по теме:  Как убрать закрепленные сообщения в Телеграмм в телефоне Андроид

При деплое в ansible в config файле, на основе которого создается файл prealpha.js, production.js — vitaly_test_config.js например в репозитории https://bitbucket.org/sbertechspb/configs/src требуется добавить также поле url

Пример файла development.js, при котором происходит успешный старт

module.exports = < telegramBotToken: «588143760:AAEjsGv8eirVN2CAmnBRQtIKsqrycWQCwXw», bot_server: < port: 8443 >, url: «https://172.104.134.141:8443» >;

Для старта через webhook на сервере в папке bot в корне должна лежать папка certs с приватным ключом и сертификатом, созданными через openssl genrsa -out webhook_pkey.pem 2048 openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem

Технический стек и ссылки

Актуальные User, Questionnaire и Category можно смотреть в src/database/models

При миграции создается модель User, Questionnaire и Category. Questionnaires заполняется из файла отдельным скриптом миграции, в этот же момент динамически расчитывается модель Category и тоже записывается в БД.

  • NodeJS
  • Vue.js
  • MongoDB
  • pm2
  • Docker

Полезные ссылки о ботах

  • Официальная документация
  • Bot API: часто задаваемые вопросы
  • Лимиты Telegram bot API и работа с ними на Go (habr)
  • Пишем бота для Telegram на языке Python (книга)
  • Node.js Telegram Bot API
  • Плейлист с видео по созданию telegram-бота
  • Видео. Боты в telegram. Зачем они нужны?

Ссылки по nodejs

  • https://github.com/sergtitov/NodeJS-Learning/blob/master/README.md
  • https://learnnode.com
  • https://egghead.io/technologies/node

Источник: github.com

Как реализовать end-to-end-тестирование telegram-бота

Каждый, кто когда-либо писал telegram-ботов, задавался вопросом: «А как их тестировать?» Сложно найти однозначный ответ. Например, при написании тестов для веб-приложений и API можно воспользоваться тестовым клиентом DRF или FastAPI: просто пишешь запрос и делаешь assert на полученный ответ. Мне захотелось получить подобный функционал и для тестирования telegram-бота.

Привет, Хабр. Я Михаил Выборный, python-разработчик, backend-developer в облачном провайдере beeline cloud. В этой статье я хочу поделиться опытом написания автоматизированных end-to-end-тестов без эмуляции Telegram Bot API, но с использованием тестовых аккаунтов. Мы зайдем в изолированное тестовое пространство Telegram, создадим тестового бота, подготовим фикстуру для запуска нашего приложения и напишем авторизацию для тестовых клиентов.

По ходу статьи я буду использовать инструменты следующих библиотек:

  • Python Telegram Bot — для написания бота (сокращенно PTB);
  • Pytest — для организации тестов;
  • Anyio — для асинхронных тестов и фикстур;
  • Pyrogram — для отправки тестовых сообщений;
  • asyncio.Event — для оповещения о получении ожидаемых сообщений и предотвращения излишних ожиданий;
  • contexlib — для удобного синтаксиса написания контекстных менеджеров.

Статья написана на примере реализации несложного бота для хранения фотографий и отправки их в ответ при запросе. Вы можете посмотреть исходный код приложения и тестов на GitHub. Ниже я использую короткие выдержки из официальной документации Telegram на английском – к ним даю пояснения на русском своими словами.

Альтернативы

Перед тем как что-то писать самому, я пытался найти готовое решение и был уверен, что Google мне поможет. Но оказалось, что готового оптимального решения просто не существует. Здесь я кратко перечислю то, что мне удалось найти и почему это не подошло.

  • больше не поддерживается
  • интеграция с unittest (не pytest)
  • подходит для тестирования ботов, написанных только на aiogram
  • реализует unit-тестирование через Mock-объекты (без интеграции Telegram Bot API)

Все тест-кейсы описываются как вызов конкретных handler-ов, из-за чего нет возможности протестировать их поведения целиком — от отправки пользователем сообщения до получения ответа. К примеру, непонятно, как тестировать фильтрацию входящих сообщений и их распределение по различным handler-ам и т. п.

  • также не поддерживается
  • тянет устаревшие зависимости (pyrogram < 2.0.0 typing-extensions < 4.0.0)
  • практически отсутствует документация

Перед тем как начать. Регистрация APP

Предположим, наш бот уже готов и мы переходим к тестированию. Для этого мы подготовим необходимые инструменты, чтобы написание самих тестов было кратким и понятным. Отправить сообщение, получить ответ, проверить его. Да, придется потратить время, чтобы реализовать вспомогательные фикстуры по регистрации клиентов и обработки входящих сообщений.

Но, заморочившись однажды, мы сможем писать сами тесты всего в несколько строк. Их будет легко обновлять и поддерживать.

Отправлять тестовые сообщения мы будем с помощью Pyrogram. Для этого нужно зарегистрировать будущее клиентское приложение.

Тут важно понимать, что для взаимодействия с Telegram API необходимо зарегистрировать свое приложение в системе Telegram — для этого потребуется действующий номер телефона. Но для запуска самих тестов будут использоваться тестовые телефонные номера. Поэтому переживать за сохранность личных данных или получение флуд-бана не стоит.

После регистрации мы получаем api_key и api_id, которые можем использовать для создания множества клиентских приложений.

Тестовый бот

Регистрация бота

Как это сделать, можно прочитать тут. Я использовал приложение Telegram для iOS, кликнув 10 раз на иконку Settings (Настройки).

https://api.telegram.org/bot/test/METHOD_NAME

Запуск бота во время тестов

Теперь при запуске тестов мы можем запустить наше приложение в тестовом пространстве. Для этого подготовим фикстуру.

Еще по теме:  Как посмотреть последнюю активность в Телеграмме если скрыли

Обычно для запуска приложения мы используем app.run_polling(), но это заблокирует дальнейшее исполнение программы. Мы же будем запускать тесты в параллель с тем, как работает наш бот. Подробнее о том, как запускать PTB с другим асинхронным кодом, — Running PTB alongside other asyncio frameworks

pytest сам по себе не асинхронный, но может работать с асинхронными тестами и фикстурами, если добавить pytestmark = pytest.mark.anyio. Подробнее: Testing with AnyIO

PTB на данный момент не поддерживает работу бота в тестовом пространстве, но можно передать токен вместе с приставкой /test. Класс telegram.Bot формирует базовый путь сложением base_url и token.

# content of /telegram/_bot.py self._base_url: str = base_url + self._token self._base_file_url: str = base_file_url + self._token

Перехватывание исключений

По умолчанию все необработанные исключение в PTB пишутся в лог. Но при запуске тестов мы хотим убедиться, что в приложении не возникало ошибок.

Для этого добавим обработчик ошибок, где будем сохранять возникшие исключения в отдельное место (в моем случае это переменная класса). Позже мы сможем проверить на наличие непредвиденных исключений.

async def collect_app_exceptions_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE): self.collected_exception = context.error self.collection_event.set() # special asyncio event we are wating for while collecting replyes raise ApplicationHandlerStop # prevent any other error handlers app.add_error_handler(self.collect_app_exceptions_callback)

collection_event объект класса asyncio.Event — событие, исполнение которого мы ожидаем, пока ждем ответа от бота. В случае перехватывания исключений ждать ответа дальше смысла нет, так как произошла ошибка. Но pytest об этой ошибке ничего не знает, поэтому сохраним ее здесь и сделаем re-rise позже. Вы увидите инициализацию и полное применение collection_event в следующем блоке.

Отлично, наш бот работает. Теперь можем отправлять ему тестовые сообщения. Для этого понадобится аккаунт.

Тестовый клиент-аккаунт

Тестовые номера

Для тестирования приложения мы будем использовать тестовые номера, которые предоставляет Telegram. Мы можем сформировать тестовые номера заранее и хранить их, к примеру, в .env файле или генерировать на лету для каждой тест-сессии отдельно. Тестовый номер — это:

99966XYYYY X — номер номер DC от 1 до 3 Y — любая цифра от 0 до 9

Тестовый номер позволяет в автоматическом режиме проходить авторизацию, и мы можем создать сколь угодно много аккаунтов. К примеру, мой бот позволяет давать другим людям доступ к общей базе фотографий. Так я смогу протестировать, что один клиент загрузил фотографию, другой получил к ней доступ, а третий нет.

Telegram периодически сбрасывает тестовые номера, поэтому все дальнейшие действия по авторизации и настройке telegram-клиента лучше производить непосредственно перед каждым запуском тестов.

Создание клиента

Для упрощенной регистрации клиентов и перехватывания всех сообщений от бота отдельно для каждого клиента я инкапсулировал всю логику в отдельный класс ClientIntegration. Но в примерах здесь я удалил все опциональные настройки, чтобы не отвлекаться от сути. Код вспомогательного класса целиком можно посмотреть тут.

  1. Создадим клиента. В отличие от PTB, у Pyrogram есть нативная поддержка тестового пространства Telegram.

self.client = Client( ‘test-client’, api_id=», api_hash=», test_mode=True, in_memory=True, phone_number=’99966′ + ‘1’ + ‘2023’, phone_code=’1′ * 5, )

  • in_memory — после авторизации сессия не будет записываться в файл test-client.session, а останется в памяти. Это позволит изолировать тесты друг от друга и не подчищать *.session файлы вручную после тестов.
  • phone_code — код подтверждения авторизации. Для тестовых номеров всегда равен номеру DC х 5 раз.
  1. Мы уже указали телефонный номер и код подтверждения. Но может быть такое, что тестовый номер не зарегистрирован. В этом случае Pyrogram попросит ввести имя и фамилию. Чтобы пройти процесс регистрации автоматически, заменим stdout и stdin:

def mock_input_callback(prompt: str = »): if ‘Enter first name: ‘ == prompt: return » if ‘Enter last name (empty to skip): ‘ == prompt: return » raise ValueError(prompt) def mock_print_callback(self, *args, **kwargs): . with pytest.MonkeyPatch.context() as monkeypatch: monkeypatch.setattr(builtins, ‘input’, mock_input_callback) monkeypatch.setattr(builtins, ‘print’, mock_print_callback) .

  1. Теперь мы можем запустить приложение клиента Pyrogram. Для удобства я описал все действия в отдельном методе ClientIntegration и обернул его в asynccontextmanager. Я использую здесь контекст-менеджер, чтобы явно описать setup и teardown. Позже это будет удобно интегрировать в Pytest в качестве yield фикстуры.

Если для авторизации клиента использовать случайно сгенерированный тестовый номер, то стоит учесть, что другой разработчик мог установить двухфакторную авторизацию для этого номера, защитив его паролем. В таком случае остается только попробовать любой другой номер.

4. В итоге можем использовать ClientIntegration.session_context для описания фикстур.

Я использую параметр scope=’session’, чтобы инициализировать клиента один раз для всей сессии. Это сократит время на подготовку фикстур, а поскольку сам клиент не хранит данные, это не нарушит изолированности тестов.

Еще по теме:  Как вести музыкальный канал в Телеграме

Тестирование

Сборщик ответов

Но как долго нам ждать ответа от бота? Можно задать максимальное значение timeout, а можно указать конкретное количество. К примеру, сейчас ожидаем получить только одно сообщение, и как только оно будет получено, можно двигаться дальше.

# messages collector: async def collect_replyes_callback(self, client: Client, message: Message) self.collected_replyes.append(message) # If True, set event flag to True. No more waiting for messages: if len(self.collected_replyes) == self.collection_required_amount: self.collection_event.set() # timeout checker: async def collection_max_timeout_waiting(self, timeout: float): await sleep(timeout) self.collection_event.set() # apply handler and create Event: self.client.on_message(filters.chat(»))(self.collect_replyes_callback) self.collection_event = asyncio.Event() # Wait until all messages are received or reaching timeout. timout_task = asyncio.create_task(self.collection_max_timeout_waiting(timeout)) await self.collection_event.wait() timout_task.cansel()

Теперь мы можем проверить полученные сообщения и то, что в приложении не было ошибок (мы использовали error_handler при инициализации приложения PTB в предыдущем блоке).

if self.collected_exceptions: raise self.collected_exception assert len(self.collected_replyes) == amount, ‘Received unexpected messages amount. ‘

Описание тестов

К примеру, мы хотим протестировать отправку сообщения /start и получение ответа Hello, !. Благодаря фикстурам, описанным выше, этот тест-кейс может быть описан буквально тремя строчками.

pytestmark = [ pytest.mark.anyio, pytest.mark.usefixtures(‘application’) # PTB Application ] async def test_start_handler(integration: ClientIntegration): # test action: async with integration.collect(amount=1) as replyes: await integration.client.send_message(», ‘/start’) # at __aexit__ wait until all messages are received # test assertion: assert replyes[0].text == f’Hellow, !’

В качестве альтернативы Pyrogram может быть Telethon. Это схожая библиотека для работы с клиентом Telegram. Из плюсов — Telethon реализует метод conversation, что упрощает сборку ответов клиенту от бота. Подробнее можно посмотреть тут.

with client.conversation(») as conv: await conv.send_message(«/start») reply: Message = await conv.get_response() assert reply.raw_text == f’Hellow, !’

Заключение

Потратив дополнительное время на подготовку фикстур, мы получаем все необходимые инструменты для написания тестов от начала и до конца. Мы можем создать несколько пользователей, отправлять им разные тестовые сообщения и проверять ответы.

Это удобно не только для написания тестов в целом, но и во время разработки — как точка входа для запуска и отладки. Вместо того чтобы каждый раз доставать телефон и вручную отправлять сообщения боту, можно описать простой тест на отправку сообщения клиентом.

Но стоит понимать, что такой способ тестирования не самый дешевый с точки зрения реализации, поддержки и времени исполнения самих тестов. Каждый запрос на регистрацию клиента, отправку сообщения клиентом, на отправку ответа ботом происходит посредством реальных запрос к серверу Telegram. А это занимает время. Когда подобных тестов станет много, это может стать проблемой. Вот почему для написания тестов стоит придерживаться парадигмы Testing Pyramid и реализовывать подобным методом только базовые и важные функции вашего приложения.

  • Блог компании beeline cloud
  • API
  • Тестирование веб-сервисов

Источник: habr.com

Создаем телеграм-бота с использованием Spring Boot Pt.2: Quiz Bot

Далее мы создадим пакет bot/handler, в котором объявим интерфейс handler:

package com.whiskels.telegram.bot.handler; import com.whiskels.telegram.bot.State; import com.whiskels.telegram.model.User; import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod; import java.io.Serializable; import java.util.List; public interface Handler < // основной метод, который будет обрабатывать действия пользователя List> handle(User user, String message); // метод, который позволяет узнать, можем ли мы обработать текущий State у пользователя State operatedBotState(); // метод, который позволяет узнать, какие команды CallBackQuery мы можем обработать в этом классе List operatedCallBackQuery(); >

Создаем телеграм-бота с использованием Spring Boot Pt.2: Quiz Bot - 6

Обработчики мы создадим чуть позже, а пока давайте делегируем обработку событий новому классу UpdateReceiver , который мы создадим в корне пакета bot: ВНИМАНИЕ! Здесь и далее будут методы, которые отображаются, как List> handle(args); на деле они выглядят так, но форматтер кода их сломал:

И делегируем ему обработку в классе Bot:

Теперь наш бот делегирует обработку событий классу UpdateReceiver , но обработчиков у нас еще нет. Давайте их создадим! DISCLAIMER! Мне очень хотелось поделиться возможностями по написанию такого бота, поэтому дальнейший код (как в принципе и код UpdateReceiver) можно очень хорошо отрефакторить с применением различных паттернов. Но мы учимся и наша цель — минимально жизнеспособный бот, так что в качестве еще одного домашнего задания можно отрефакторить все, что вы увидели 🙂 Создаем пакет util, а в нем — класс TelegramUtil :

package com.whiskels.telegram.util; import com.whiskels.telegram.model.User; import org.telegram.telegrambots.meta.api.methods.send.SendMessage; import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton; public class TelegramUtil < public static SendMessage createMessageTemplate(User user) < return createMessageTemplate(String.valueOf(user.getChatId())); >// Создаем шаблон SendMessage с включенным Markdown public static SendMessage createMessageTemplate(String chatId) < return new SendMessage() .setChatId(chatId) .enableMarkdown(true); >// Создаем кнопку public static InlineKeyboardButton createInlineKeyboardButton(String text, String command) < return new InlineKeyboardButton() .setText(text) .setCallbackData(command); >>

Мы напишем четыре обработчика: HelpHandler, QuizHandler, RegistrationHandler, StartHandler. StartHandler:

RegistrationHandler:

Help Handler:

QuizHandler (самый ужасно

Источник: javarush.com

Рейтинг
( Пока оценок нет )
Загрузка ...