Библиотека тестировщика | QA, тестирование, quality assurance, manual testing, autotesting, ручное тестирование, автотесты
8.94K subscribers
2.07K photos
254 videos
118 files
3.56K links
Все самое полезное для тестировщика в одном канале.

Наши курсы: https://clc.to/wlBkTA

По рекламе: @tproger_sales_bot

Учиться у нас: https://proglib.io/w/12538d6f

Для обратной связи: @proglibrary_feeedback_bot
Download Telegram
☔️ Планы на выходные снова испортила погода? У нас есть план получше.

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

📍 В Proglib Academy покупаешь один курс, а второй получаешь в подарок. Платишь только за один!

Вот несколько сочетаний:

💥 ⁠Разработка ИИ-агентов + ⁠Python
💥 ⁠Machine Learning + ⁠Математика для Data Science

Можно выбрать и другие курсы — под свои интересы и цели.

⏳ Акция действует до 18 октября.

➡️ ⁠Выбрать курсы и оставить заявку
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Тестируем не запрос, а цепочку действий

В учебной корзине добавление работает. При удалении товар исчезает, а общая цена остаётся прежней. Одиночный happy path этого не показывает.

Проверка модели
— Храним простой эталон корзины.
— Hypothesis выбирает цепочки add/remove.
— После каждого шага сравниваем итог с суммой позиций модели.

В проверенном примере Hypothesis 6.169 сократил сбой до add(pen) → remove(pen): товара нет, сумма всё ещё 20. Исправленный вариант прошёл прогоны с max_examples=50 и stateful_step_count=20.

Найденную цепочку сохраняем как регрессионный пример. Успешный прогон не доказывает корректность всех сценариев.

Документация

Навигация: Вакансии

Библиотека тестировщика

#теория_на_пальцах
❤2
Два NULL при UNIQUE. Это баг?

В PostgreSQL 18 у необязательного поля external_id стоит обычный UNIQUE. Вы создаёте две записи без внешнего идентификатора, в обеих сохраняется NULL. База принимает их. Заводим дефект?

Подсказка: уникальность и обязательность значения — разные требования.

Сам по себе второй NULL не нарушает обычный UNIQUE в PostgreSQL 18. По умолчанию два NULL не считаются равными при этой проверке. Если по требованиям допустим только один NULL, проверьте вариант UNIQUE NULLS NOT DISTINCT. Если значение обязательно, нужен NOT NULL.

Перед выводом сверяйте требования с реальным DDL таблицы. Проверьте три случая: два одинаковых непустых значения, два разных и два NULL.

Отдельно посмотрите, что API сохраняет из пустой строки и отсутствующего поля запроса. Это разные входные данные, и приложение может их преобразовывать. Поведение PostgreSQL не стоит переносить на все СУБД.

Ограничения в PostgreSQL 18

#теория_на_пальцах
❤1👍1
Checks красные, а CI зелёный

В отчёте k6 есть неуспешные проверки ответов, но шаг CI завершился успешно. Прежде чем искать ошибку в пайплайне, посмотрите на thresholds.

check фиксирует результат проверки. Сам по себе он не меняет код завершения k6. Критерий провала всего прогона задаёт threshold по метрике.

Например, в скрипт с checks можно добавить такой учебный порог:

export const options = {
thresholds: {
checks: ['rate>0.9'],
},
}


Он требует больше 90% успешных checks. Ровно 90% уже не проходит. Если хотя бы один threshold нарушен, k6 завершает прогон с ненулевым кодом. Шаг CI должен учитывать этот код.

Число 90% здесь показывает синтаксис, а не рекомендуемую планку качества. Порог выбирают из требований продукта. То же относится к http_req_duration: ['p(95)<200']: это пример ограничения 95-го перцентиля времени запросов в миллисекундах.

Порог не задаёт профиль нагрузки. Зелёный результат одного прогона не доказывает, что сервис выдержит любое число пользователей.

Checks и thresholds в документации k6

#тест_драйв
❤3
😎 Выбираешь один курс, второй получаешь бесплатно. Баг? Нет, акция!

До 31 октября в Proglib Academy можно выбрать два курса и заплатить только за один.

Например, можно совместить:

💥 ИИ для разработчиков — применение нейросетей в повседневной разработке: работа с кодом, тестирование и ревью.

💥 Разработка ИИ-агентов — архитектура агентов и создание собственных AI-решений.


Вместе курсы стоят 108 000 ₽, но по акции оба обойдутся в 59 000 ₽. Экономия — 49 000 ₽ 🔥

Интересуют Python и ИИ или алгоритмы и архитектура? Можно выбрать любые два курса из каталога.

Акция действует до 31 октября включительно ⏳

⏬ Собрать свой учебный билд
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Первый тест ждал 503, второй сразу получил 200

Учебный мок WireMock устроен так: первый запрос возвращает 503 и переводит сценарий из Started в Recovered. Следующие запросы в этом состоянии получают 200.

Один тест прошёл эту цепочку. Следующий ждёт исходный 503, но получает 200. В такой ситуации проверьте, не осталось ли состояние от предыдущего теста.

В JSON поле requiredScenarioState задаёт состояние, в котором подходит заглушка. newScenarioState переводит сценарий дальше. Само начало нового теста не означает возврата к Started.

Перед повтором сценария
— Посмотрите текущее состояние через GET /__admin/scenarios.
— На изолированном тестовом экземпляре пустой POST /__admin/scenarios/reset сбрасывает все сценарии.
— Для одного сценария, например retry, используйте пустой PUT /__admin/scenarios/retry/state.

Общий reset может сбросить состояние соседнего параллельного теста. Поэтому для параллельных прогонов нужна изоляция экземпляров или сценариев, а не только сброс «перед каждым тестом».

Цепочка 503 → 200 проверяет поведение клиента на заданных ответах мока. Восстановление настоящего внешнего API она не подтверждает.

Состояния и сброс сценариев WireMock

#теория_на_пальцах
👍1
Горизонтальный скролл при увеличении: когда это дефект

Страница при 100% выглядит аккуратно. Увеличиваете масштаб — и для чтения каждой строки приходится двигать её вправо и влево. Для обычного вертикального контента это повод проверить reflow.

Критерий WCAG 2.2 1.4.10, уровень AA требует при ширине, эквивалентной 320 CSS px, сохранять информацию и функции без прокрутки в двух направлениях. Для частей, которым по смыслу нужна двумерная компоновка, есть исключения.

Что проверить
— Доведите CSS-ширину viewport до 320 px. Один из вариантов — исходный viewport 1280 CSS px и browser zoom 400%. Сверяйте фактическую ширину, а не разрешение экрана.
— Прочитайте текст, заполните форму, доберитесь до кнопок. Ничего не должно теряться из-за нового расположения блоков.
— Если на странице таблица или карта, определите границы исключения. Горизонтальная прокрутка такой части сама по себе ещё не доказывает нарушение.

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

Pinch zoom и увеличение только текста не равнозначны browser zoom. Этот чек-лист проверяет один критерий и не подтверждает соответствие всему WCAG.

Официальное объяснение Reflow от W3C

#теория_на_пальцах
❤2
Warning тоже можно проверить тестом

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

В pytest фикстура caplog даёт доступ к записям логов. В record_tuples каждая запись — это имя logger, числовой уровень и уже сформированное сообщение.

import logging


def reject_payment():
logging.getLogger('payments').warning('payment rejected: %s', 'timeout')


def test_warning_is_contract(caplog):
with caplog.at_level(logging.WARNING, logger='payments'):
reject_payment()
assert ('payments', logging.WARNING, 'payment rejected: timeout') in caplog.record_tuples


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

Если захват пуст, проверьте настройку logging: dictConfig может удалить обработчик caplog с root logger. Для записей из другой стадии теста используйте get_records('setup') или соответствующее имя стадии.

Это учебный logger. Показанный тест и проверка отсутствия записи без вызова функции прошли на pytest 9.0.3: 2 passed. Реальная платёжная система здесь не тестировалась.

Работа с логами в pytest

#тест_драйв
❤2👍1
📌 Один курс — хорошее вложение в себя. Два по той же цене — ещё лучше.

В Proglib Academy действует акция: покупаешь один курс, а второй получаешь в подарок.

Например, можно совместить два направления по работе с ИИ:

💥 ИИ для разработчиков — применение нейросетей в повседневной разработке: работа с кодом, тестирование и ревью.

💥 Разработка ИИ-агентов — архитектура агентов и создание собственных AI-решений.


📍 Разница в цене — почти 50 тысяч рублей. Можно освоить больше, не выходя за рамки запланированного бюджета.

А если тебе интереснее Python, алгоритмы, backend или DevOps — выбирай другую пару курсов из каталога.

Акция действует до 31 октября включительно ⏳

⏮️ Пора прокачать свой стек
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Данные в UI есть, а page.route молчит

Мок Playwright не срабатывает, хотя страница показывает данные. Один из возможных участников цепочки — Service Worker. В документации Playwright отдельно разобран случай с MSW: его Service Worker забирает запросы, и они становятся невидимыми для page.route() и browserContext.route().

Для теста, которому нужен перехват средствами Playwright, документация предлагает блокировать Service Workers. Настройка Playwright Test:

import { defineConfig } from '@playwright/test'

export default defineConfig({
use: { serviceWorkers: 'block' },
})


Перехват задавайте до действия, которое отправляет запрос. Если при заблокированном SW обработчик начал получать запросы, это повод разобраться с маршрутом запроса в исходной среде. Само по себе это не диагноз «баг приложения».

У такой проверки есть цена: среда изменилась. Прогон с serviceWorkers: 'block' не проверяет настоящий путь через SW, его кеш и offline-поведение. Для них нужен отдельный сценарий со включённым Service Worker.

Почему Service Worker влияет на перехват

#тест_драйв
❤1
202 Accepted: выгрузка ещё не готова

Сервис экспорта ответил 202. Проверка только кода ответа пропустит задачу, которая позже упадёт.

202 означает, что запрос принят, но обработка ещё не завершена и могла даже не начаться. Успех обработки он не гарантирует.

Для такого API проверьте отдельно приём запроса, конечный статус задачи и итоговый файл: доступен ли он и те ли данные внутри. Проверьте и случай, когда задача завершилась ошибкой.

В примере MDN ответ содержит taskId и monitorUrl для проверки статуса. Эти поля задаёт контракт конкретного приложения, они не обязательны для любого ответа 202. Дедлайн ожидания тоже берите из контракта API.

202 в MDN

Навигация: Вакансии
Библиотека тестировщика

#теория_на_пальцах
Один список на два теста в pytest

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

pytest передаёт параметры как есть, без копирования. Если два случая ссылаются на один list или dict, мутация в одном вызове будет видна следующему. Два отдельно созданных списка с одинаковыми значениями остаются разными объектами.

Сравните результаты запуска одного случая и всего набора и проверьте, откуда берётся объект. Для независимых данных создавайте новую структуру на каждый вызов через fixture или factory. Обычная поверхностная копия не изолирует вложенные списки.

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

Правило pytest

Навигация: Вакансии
Библиотека тестировщика

#тест_драйв
Контейнер running, а сервис ещё отвечает 503

В интеграционном тесте контейнер уже запущен, TCP-порт открыт, а нужный HTTP-запрос всё ещё получает 503. Чего ждать перед тестом?

В Testcontainers for Java startup strategy проверяет состояние запуска. Wait strategy проверяет готовность к работе теста. У GenericContainer базовое ожидание — пока первый mapped port не начнёт слушать.

Если тесту нужен готовый HTTP-сервис, дождитесь ответа его endpoint с оговорённым статусом. Путь /health и код 200 в схеме — условия учебного сервиса. Ответ 200 говорит только о том, что проверяет этот endpoint.

Добавьте проверку: порт открыт, endpoint ещё не готов. Проверьте timeout и диагностику. Значения по умолчанию Java GenericContainer не стоит переносить на все языки и модули.

Startup и wait strategies

Навигация: Вакансии
Библиотека тестировщика

#теория_на_пальцах