Валерий | AQA Engineer | Автотестирование на Python | REST, gRPC, GraphQL – Telegram
Валерий | AQA Engineer | Автотестирование на Python | REST, gRPC, GraphQL
1.42K subscribers
165 photos
156 videos
1 file
185 links
Сделаю из тебя крутого AQA инженера на Python.

• Преподаю лучшие тренинги по автоматизации тестирования API
• Senior Python developer | AQA lead, 7 лет в IT
Download Telegram
Как сделать удобно расширяемый http клиент?

Самый частый паттерн при написании логгирующей http обертки в API автотестах:
import httpx

class LogClient(httpx.Client):
def request(self, *args, **kwargs):
print(args, kwargs)
response = super().request(*args, **kwargs)
print(response.content)
return response


Потом добавляем allure степы:
class LogClient(httpx.Client):
def request(self, *args, **kwargs):
with allure.step(f"Request {args}"):
print(args, kwargs)
allure.attach(request, name="Request")
response = super().request(*args, **kwargs)
allure.attach(response, name="Response")
return response

Метод разрастается, мы опять вносим изменения в класс.
Дальше захотим добавить coverage, метрики - опять изменения.

Может быть есть способ не изменяя класс?

Решение 1: Встроенные hooks в httpx
client = httpx.Client(
event_hooks={
'request': [log_request],
'response': [log_response]
}
)

httpx уже поддерживает event hooks.
Можем передать функции, которые вызовутся до/после запроса.

Решение 2: Своя реализация

А что если захотим свой клиент?
Систему хуков можно внедрить в любой клиент - к БД или другому ресурсу.
Рассмотрим на примере httpx, как будто там нет хуков:
from typing import Callable
import httpx
from httpx import Request, Response

class Client:
def __init__(self):
self._on_request_callbacks = []
self._on_response_callbacks = []
self._client = httpx.Client()

def add_request_hook(
self, callback: Callable[[Request], None]
) -> None:
self._on_request_callbacks.append(callback)

def add_response_hook(
self, callback: Callable[[Response], None]
) -> None:
self._on_response_callbacks.append(callback)

def _run_hooks(self, value, hooks):
for hook in hooks:
try:
hook(value)
except Exception as e:
print(f"Hook error: {e}")

def request(self, method, url, **kwargs) -> Response:
request = self._client.build_request(
method=method, url=url, **kwargs
)

self._run_hooks(request, self._on_request_callbacks)
response = self._client.send(request)
self._run_hooks(response, self._on_response_callbacks)

return response


Создаем колбеки:
def log_req(request):
print(f"→ {request.method} {request.url}")

def log_resp(response):
print(f"← {response.status_code}")

def allure_req(request):
allure.attach(str(request), name="Request")

def allure_resp(response):
allure.attach(response.text, name="Response")


Регистрируем и используем:
client = Client()
client.add_request_hook(log_req)
client.add_request_hook(allure_req)
client.add_response_hook(log_resp)
client.add_response_hook(allure_resp)

client.request("GET", "https://httpbin.org/get")


Результат:

→ GET https://httpbin.org/get
← 200


Что получается?

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

——————————-

📱 TG-сообщество

📱 Обучение

📱 Отзывы
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11
Как удобно тестировать брокеры сообщений?

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

Как можно улучшить, чтобы переиспользовать соединение и при этом проводить валидацию моментально при наступлении события? При этом делать это расширяемо и удобно.

Мы можем пойти немного в инженерию.

А что если у нас будет один Kafka listener, который будет вычитывать Kafka топики, и несколько подписчиков, которые при получении события (например, сообщения) будут выполнять свою логику?

Так мы с вами реализуем паттерн Observer.

Сначала реализуем Subject или наш KaflaListener, для простоты там будет один метод publish, который и будет уведомлять подписчиков Observer о наступлении событий.
Этот класс так же имеет метод регистрации подписчиков, которых можно сделать очень много.

class KafkaListener:
def __init__(self):
self._clients: list[Subscriber] = []
self._is_running: bool = False

def start(self):
if self._is_running:
raise RuntimeError("already running")

self._is_running = True

def publish(self, message: str) -> None:
for client in self._clients:
client.read_message(message)

def subscribe(self, client: Subscriber) -> None:
if self._is_running:
raise RuntimeError("already running")

self._clients.append(client)


Дальше опишем интерфейс наших подписчиков.
from typing import Protocol


class Subscriber(Protocol):
def read_message(self, message: str) -> None: ...


Теперь описываем конкретные подписчики, где можем сказать что делать при выполнении read_message, например валидацию или перекладывание в очередь.

class FirstClient:
def read_message(self, message: str) -> None:
print(f"Get message from {self.__class__.__name__}, {message}")


class SecondClient:
def read_message(self, message: str) -> None:
print(f"Get message from {self.__class__.__name__}, {message}")


class ThirdClient:
def read_message(self, message: str) -> None:
print(f"Get message from {self.__class__.__name__}, {message}")


Теперь мы можем увидеть, что при publish от нашего listener, наше сообщение попадет сразу во все подписчики.
kafka = KafkaListener()
kafka.subscribe(FirstClient())
kafka.subscribe(SecondClient())
kafka.subscribe(ThirdClient())

for _ in range(10):
kafka.publish(f"message {_}")
time.sleep(2)


Получим такой результат:
Get message from FirstClient, message 0
Get message from SecondClient, message 0
Get message from ThirdClient, message 0
Get message from FirstClient, message 1
Get message from SecondClient, message 1
Get message from ThirdClient, message 1
...


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

Изучение данного паттерна уже включено в курс по брокерам сообщений, который выйдет после Нового года.

А пока вы можете изучить другие паттерны, такие как Proxy, Facade, Decorator, в курсе Advanced.
1🔥72
Хочу поделиться некоторыми слайдами из своего будущего тренинга по брокерам сообщений.

В частности, базовых проблем которые возникают при работе с Kafka в автоматизации тестирования.

А как вы тестируете и какой подход используете?

——————————-

📱 TG-сообщество

📱 Обучение

📱 Отзывы
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥14
Привет, давненько меня не было.

Так вот, хочу рассказать о чем. Пару лет назад у меня возникла идея разработать опенсорс-фреймворк, что-то типа Django или FastAPI. То есть, что-то, что позволит быстро и удобно разработать автотесты. У меня было несколько подходов, и я даже написал такой фреймворк, который уже есть на PyPI, но не скажу, как он называется.)))

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

Так появились инструменты restcodegen, который по Swagger-спеке генерирует Python-клиенты. Эта библиотека в отрефакторенном виде сейчас присутствует в нашей Python-платформе, и я знаю, что используется некоторыми людьми в проектах за пределами Ozon.

Вторая важная задача заключалась в удобной кодогенерации для gRPC. Подход к генерации gRPC-кода в виде плагина я подсмотрел в нашей же Python-платформе, но чтобы сделать это open source, разработал механизм для получения proto-файлов через gRPC-рефлексию. Теперь, зная хост или IP-адрес, можно легко получить Python-клиент для выбранного gRPC-сервиса.

Так появился инструмент pbreflect, и доклад про него вы можете посмотреть здесь.

Эти инструменты будут полезны любому Python-разработчику веб-приложений.

Теперь настал этап интеграции этих инструментов в сам фреймворк для разработки автотестов. Уже готова часть для работы с REST API. Сколько он экономит времени, зависит от размера вашего API, ведь по одной спецификации генерируются клиенты, тесты и фикстуры. Пользователю остается только заполнить хост своего сервиса, и дальше все, в принципе, работает. Про сам инструмент расскажу позже. Что меня удивило, так это то, что за неделю количество скачиваний составило больше 600. Пока это рекорд из всех моих библиотек. Некоторым подписчикам я уже даже дал потестить, но прошу здесь не спойлерить, об этом расскажу позже!
🔥12👍52
Привет!
Как и обещал - зарелизнул первую итерацию своего фреймворка для генерации автотестов.
Что он уже умеет?

Берёшь свою swagger/openapi спеку, одна команда и у тебя готов:
- проект с клиентами
- фикстурами
- тестами
- конфигами.

Без нейросетей, чистый, детерминированный результат.

По факту:
• создает проектную структуру
• пишет фикстуры
• пишет тесты
• пишет конфигурацию
• и всё это одной командой

Погонять можно уже сейчас, фреймворк рабочий.
А как им пользоваться - скоро запишу занятие в ступень Профешнл.

С момента релиза - почти 1000 скачиваний, практически без рекламы.
Если не заброшу (а я вроде не собираюсь) - кто знает, может когда-нибудь станет таким же популярным, как FastAPI. А чего нет?)

Следующая итерация: gRPC + Postgres.
Посмотреть пример проекта, который генерится одной командой - вот тут, достаточно только указать URL сервиса и всё взлетает 🔥
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍9
Привет ребят, сегодня такой завал, хотелось подвести какие-то итоги, но наверное уже не успею)

По поводу чего спросите вы?
Сегодня у меня День Рождения)

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

А я и дальше смогу делиться с вами хорошим техническим контентом и классными тренингами)

Спасибо что в этот день вы со мной)
1🔥375
🎆Сегодня День Рождения телеграмм каналу @protestinginfo!
5️⃣😚☺️😝!

2 декабря был день рождения аккаунту protestinginfo в нельзяграме!
Также присоединяйтесь. 💻

Ровно 5 лет назад я укладывала старшего сына спать (ему было 2 месяца) и думала о работе, скучала. И сейчас скучаю, хотя скоро выхожу на частичную занятость в декрете 🔥

Так вот, я думала, что начинаю забывать основы тестирования, плюс, казалось, что дни становятся однообразными, и я загорелась желанием завести блог по тестированию.
Я начала придумывать, а как же назвать мой аккаунт, первое, что пришло в голову «ND_testing» (ND - Nadezhda Dudnik), потом начала смотреть какие ещё каналы по тестированию есть, и их оказалось много, и, по наблюдению, я придумала «ProTestingInfo»😉.
Затем я начала думать, как же нарисовать мой первый логотип.

Я изначально хотела, чтобы логотип был тёмно-синий - мой любимый цвет.
В оформлении постов мне помогает и поддерживает моя сестра Любочка, и эта картинка с днем рождения оформлена ею.

Я горела желанием собирать любую информацию, помогать себе и другим людям.
Мне нравится придумывать тесты, проводить вебинары, а сейчас есть не только курс по подготовке к собеседованиям и мини-программы, а курсы по тестированию бэкенда, тестированию gRPC API, GraphQL API, и хочется отдельно выразить благодарность Валерию Меньшикову за наше партнерство.
Занимаюсь менторской деятельностью, и более 40 менти получили оффер за 2025г, и до сих пор направляю людей, пока есть возможность.

🩷Хочу выразить благодарность коллегам-блогерам, которые рекомендуют мой блог, мне очень приятно и также ценю.
💚Также я хочу выразить огромную благодарность всем вам, что подписались на мой канал, я это очень ценю!🤗💜

❤️Хочу поблагодарить за то, что вы со мной. Спасибо, что читаете, поддерживаете, крепко всех обнимаю.🥰

Я также буду продолжать заниматься созданием тестов, написанием полезных постов и статей!
Делиться полезной информацией!😎

Спасибо за ваши отзывы.
Люблю свое дело🫶.

Желаю всем вам развития!❄️

Благодарю за ваши реакции, комментарии и обратную связь. Ценю.

А кто недавно на моем канале, предлагаю прочитать пост про знакомство.
Будем дальше закреплять наши знания ⚡️!
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
51🔥91👍1
Всем привет! У кого, как и у меня, работы под конец года подвалило
Я тут с подарочками)

Во-первых, я закончил записывать курс по тестированию брокеров сообщений ✍️.
Знаю, многие ждали - видео полностью готовы (самая сложная часть позади). Осталось залить на платформу и наваять лендинг.

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

pbreflect - пофиксил баги, которые были связаны с использованием annotation.proto, и библиотека стала стабильнее.

Выпустил новый релиз e2efast - теперь фикстуры резолвятся автоматически и без багов (по крайней мере пока).
Планирую добавить, чтобы в конфиг автоматически проливался хост, а не руками заполнять.
Но для этого надо поправить парсер в restcodegen, поэтому пока всё по-старинке — хост руками.

Напомню:
restcodegen - библиотека для генерации клиента к REST API по спецификации OpenAPI 3
pbreflect - библиотека для получения протофайлов по URL с использованием gRPC-рефлексии и генерации клиентов
e2efast - фреймворк для быстрого развертывания каркаса автотестов для REST-сервисов (генерация клиентов, фикстур, тестов)

В общем: пользуемся, говорим спасибо 😎 и ждём открытия продаж курса по брокерам!

——————————-

📱 TG-сообщество

📱 Обучение

📱 Отзывы
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥193👨‍💻1