Refactoring: step 2

- независимые функции вынесены в хелперы
- добавлены тесты на хелперы и простые команды бота
- проверка урла Правил вынесена в хелпер
- уровень логирования повышен для бота
- добавлено пара кейсов и слов в спам
- при проверке на спам идет сработка если кроме русского и препинания есть еще какие-то символы
-
This commit is contained in:
kotolex
2023-12-22 22:17:07 +05:00
parent 9103669cac
commit 52347c19f7
11 changed files with 297 additions and 81 deletions
+127
View File
@@ -0,0 +1,127 @@
import logging
from unittest import IsolatedAsyncioTestCase, main
from telebot import asyncio_helper, types, logger
from src import helpers
# нужно не дать делать реальные запросы в тестах, конкретно тут -за Правилами чата
helpers.is_url_reachable = lambda a: True
from src.commands import bot
# отключаем логи бота, в тестах они не нужны
logger.setLevel(logging.ERROR)
def get_update(text, reply_to=None):
params = {'text': text}
chat = types.Chat(id=11, type='private')
user = types.User(id=10, is_bot=False, first_name='Some User')
if reply_to:
params["reply_to_message"] = types.Message(message_id=1, from_user=user, date=None, chat=chat,
content_type='text', options={'text': reply_to}, json_string="")
mess = types.Message(message_id=1, from_user=user, date=None, chat=chat, content_type='text', options=params,
json_string="")
edited_message = None
channel_post = None
edited_channel_post = None
inline_query = None
chosen_inline_result = None
callback_query = None
shipping_query = None
pre_checkout_query = None
poll = None
poll_answer = None
my_chat_member = None
chat_member = None
chat_join_request = None
return types.Update(1001234038283, mess, edited_message, channel_post, edited_channel_post, inline_query,
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer,
my_chat_member, chat_member, chat_join_request)
# сюда будут складываться результаты, перед началом теста очищается
RESULTS = []
async def custom_sender(token, url, method='get', params=None, files=None, **kwargs):
RESULTS.append(params)
result = {"message_id": 1, "date": 1, "chat": {"id": 1, "type": "private"}}
return result
# Чтобы перехватить запросы к телеге
asyncio_helper._process_request = custom_sender
class TestBot(IsolatedAsyncioTestCase):
def setUp(self) -> None:
self.bot = bot
RESULTS.clear()
async def test_start(self):
await self.bot.process_new_updates([get_update('/start')])
self.assertEqual(RESULTS[0]['text'], "Начни с прочтения")
async def test_non_grata(self):
await self.bot.process_new_updates([get_update('как вам дударь?')])
self.assertEqual(RESULTS[0]['text'], "у нас тут таких не любят")
async def test_non_grata2(self):
await self.bot.process_new_updates([get_update('смотрю хауди')])
self.assertEqual(RESULTS[0]['text'], "у нас тут таких не любят")
async def test_rules(self):
await self.bot.process_new_updates([get_update('/rules')])
self.assertEqual(RESULTS[0]['text'], "Читай...")
self.assertTrue("https://telegra.ph/pythonchatru-07-07" in RESULTS[0]['reply_markup'])
async def test_faq(self):
await self.bot.process_new_updates([get_update('/faq')])
self.assertEqual(RESULTS[0]['text'], "Читай...")
self.assertTrue("https://telegra.ph/faq-10-07-4" in RESULTS[0]['reply_markup'])
async def test_lib(self):
await self.bot.process_new_updates([get_update('/lib')])
self.assertEqual(RESULTS[0]['text'], "Читай...")
self.assertTrue("https://telegra.ph/what-to-read-10-06" in RESULTS[0]['reply_markup'])
async def test_tr(self):
await self.bot.process_new_updates([get_update('/tr', reply_to="ghbdtn")])
self.assertEqual(RESULTS[0]['text'], "привет")
async def test_tr2(self):
await self.bot.process_new_updates([get_update('/tr', reply_to="руддщ")])
self.assertEqual(RESULTS[0]['text'], "hello")
async def test_tsya(self):
await self.bot.process_new_updates([get_update('/tsya')])
self.assertEqual(RESULTS[0]['text'], "<i>-тся</i> и <i>-ться</i> в глаголах")
self.assertTrue("https://tsya.ru/" in RESULTS[0]['reply_markup'])
async def test_nometa(self):
text = """Не задавай мета-вопросов вроде:\n<i> «Можно задать вопрос?»\n «Кто-нибудь пользовался .. ?»\n «Привет, мне нужна помощь по .. !»</i>\n\nПросто спроси сразу! И чем лучше объяснишь проблему, тем вероятнее получишь помощь."""
await self.bot.process_new_updates([get_update('/nometa', reply_to="кто тут питонист?")])
self.assertEqual(RESULTS[0]['text'], text)
async def test_neprivet(self):
await self.bot.process_new_updates([get_update('/neprivet', reply_to="привет всем")])
self.assertEqual(RESULTS[0]['text'], "Пожалуйста, не пишите просто «Привет» в чате.")
self.assertTrue("https://neprivet.com/" in RESULTS[0]['reply_markup'])
async def test_nojob(self):
text = """Мы здесь не для того, чтобы за тебя решать задачи.\n\nЗдесь помогают по конкретным вопросам в <u>ТВОЁМ</u> коде, поэтому тебе нужно показать код, который ты написал сам и объяснить где и почему застрял... всё просто. 🤷🏼️"""
await self.bot.process_new_updates([get_update('/nojob', reply_to="есть работа")])
self.assertEqual(RESULTS[0]['text'], text)
async def test_nobot(self):
text = """<b>Внимание</b>:\nТелеграм бот <i>не должен</i> быть твоим первым проектом на Python. Пожалуйста, изучи <code>основы Python</code>, <code>работу с модулями</code>, <code>основы веб-технологий</code>, <code>асинхронное программирование</code> и <code>отладку</code> до начала работы с Телеграм ботами. Существует много ресурсов для этого в интернете."""
await self.bot.process_new_updates([get_update('/nobot', reply_to="как бота написать?")])
self.assertEqual(RESULTS[0]['text'], text)
async def test_nogui(self):
text = """<b>Внимание</b>:\nGUI приложение <i>не должно</i> быть твоим первым проектом на Python. Пожалуйста, изучи <code>основы Python</code>, <code>работу с модулями</code>, <code>циклы событий</code> и <code>отладку</code> до начала работы с какими-либо GUI-фреймворками. Существует много ресурсов для этого в интернете."""
await self.bot.process_new_updates([get_update('/nogui', reply_to="как gui написать?")])
self.assertEqual(RESULTS[0]['text'], text)
if __name__ == '__main__':
main()
+73
View File
@@ -0,0 +1,73 @@
from unittest import TestCase, main
from unittest.mock import MagicMock
from src.constants import SPAM, BAN_WORDS, ADMIN_ID
from src.helpers import is_spam, is_mixed, is_ban_words_in_caption, is_in_not_allowed, is_nongrata, is_admin
CASES = (
"Оформим резидeнтствo ОАЭ без предoплаты за 5000 дирхам. Пoдробнoсти в лc",
"Всем привет Я в поисках людей в kpиптo кoмaнду У нас вы пройдете 6ecплaтноe обученue 1-3 дня Можно совмещать с основной paбoтoй"
)
class TestSpam(TestCase):
def test_simple(self):
for spam_word in SPAM:
with self.subTest(f"check spam word({spam_word})"):
self.assertTrue(is_spam(spam_word))
def test_case_first(self):
for text in CASES:
with self.subTest(f"check case({text})"):
self.assertTrue(is_spam(text))
def test_one(self):
self.assertTrue(is_spam("привeт")) # e английская
def test_is_mixed(self):
self.assertTrue(is_mixed("привeт")) # e английская
self.assertFalse(is_mixed("привет ребята!"))
class TestOthers(TestCase):
def test_ban(self):
for word in BAN_WORDS:
with self.subTest(f"check ban word({word})"):
self.assertTrue(is_ban_words_in_caption(word))
def test_allowed(self):
params = (
(True, [], 'any'),
(True, ['one'], 'two'),
(False, ['one', 'two'], 'two'),
(False, ['one', 'two'], 'Two'),
(False, ['one', 'two'], 'TWO'),
)
for expected, words, mess in params:
with self.subTest(f"check allowed({words, mess})"):
self.assertEqual(is_in_not_allowed(words, mess), expected)
def test_non_grata(self):
params = (
(False, 'any'),
(True, 'дудар'),
(True, 'хауди'),
(True, 'dudar'),
)
for expected, text in params:
with self.subTest(f"check non-grata({text})"):
m = MagicMock(text=text)
self.assertEqual(is_nongrata(m), expected)
def test_is_admin(self):
params = (
(False, 'any'),
(True, ADMIN_ID),
)
for expected, text in params:
with self.subTest(f"check non-grata({text})"):
m = MagicMock(from_user=MagicMock(id=text))
self.assertEqual(is_admin(m), expected)
if __name__ == '__main__':
main()