QA-портфолио в 2026 году: что показывать, чтобы вас вообще звали на собеседование
Вступление
Вопрос «что положить в портфолио QA» обычно сводят к списку проектов и технологий. Но для работодателя портфолио — это не витрина и не коллекция учебных заданий.
Это фильтр.
До собеседования никто не знает, как вы думаете и как принимаете решения. Единственное, что можно оценить заранее, — это артефакты вашей работы. И по ним работодатель решает простой вопрос: стоит ли вообще звать вас на разговор.
В этой статье я разберу, какие проекты действительно имеет смысл показывать в портфолио QA Automation Engineer и зачем. Без теории и без углубления в технические детали — только то, что реально работает как допуск к рынку. С конкретными примерами и пояснением, какие сигналы эти проекты дают работодателю.
Сразу обозначу рамки: здесь не будет объяснений, как писать автотесты или настраивать CI. Речь о том, что должно быть у вас в арсенале перед отправкой резюме, особенно если у вас нет коммерческого опыта или вы переходите из manual QA в автоматизацию.
Дальше я разберу несколько типов проектов — UI, API и нагрузочные тесты — и покажу, почему именно такие артефакты заметно повышают шанс быть приглашённым на собеседование. Примеры будут показаны на Python, но сама логика и требования к портфолио не зависят от языка и одинаково применимы к другим стекам.
Зачем вообще нужно портфолио?
Если у вас нет коммерческого опыта или вы переходите из manual QA в автоматизацию, у работодателя почти нет способов понять, на что вы способны. Резюме в таком случае — это набор слов, а слова на входе стоят дёшево.
Портфолио решает ровно одну задачу: даёт минимальную рабочую опору для доверия. Оно не заменяет опыт и не гарантирует оффер, но позволяет показать, что вы умеете не только учиться, а делать — пусть и на учебных или пет-проектах.
Хорошее портфолио снижает риски для работодателя. По нему видно, как вы подходите к задачам, умеете ли вы строить структуру, работать с инструментами и доводить вещи до конца. Это сразу отделяет вас от потока кандидатов с одинаковыми курсами и одинаковыми формулировками в резюме.
Важно понимать: речь не о том, чтобы показать «как можно больше». Речь о том, чтобы показать достаточный и понятный набор артефактов, которые соответствуют реальным ожиданиям рынка. Именно поэтому дальше мы будем говорить про конкретные типы проектов — UI, API и нагрузочные тесты — и разбирать, зачем каждый из них нужен и что именно он должен демонстрировать.
UI автотесты
Первый проект, который имеет смысл положить в портфолио QA Automation Engineer — это UI автотесты. Не потому что UI важнее всего, а потому что это самый прямой и понятный артефакт, по которому работодатель может быстро оценить ваш уровень «инженерности». Один и тот же набор тестов можно написать как хаотичное полотно кода, а можно — как поддерживаемую систему. И портфолио как раз должно показать второй вариант.
Хороший UI-проект в портфолио — это не «много тестов». Это небольшой, но законченный репозиторий, в котором видно, что вы умеете работать с браузерной автоматизацией (Playwright или Selenium), понимаете базовую архитектуру автотестов и отделяете тестовую логику от деталей реализации. На практике это обычно выражается в нормальной структуре проекта и использовании паттернов вроде Page Object, Page Component и Page Factory — не ради галочки, а чтобы тесты читались, переиспользовались и не разваливались при первом же изменении UI.
Рассмотрим пример на реальном репозитории: https://github.com/Nikita-Filonov/python-ui-tests.
Это UI-тесты на Python и Playwright для учебного веб-приложения UI Course. Внутри проекта нарочно собран «минимально достаточный» набор технологий и практик, которые чаще всего ожидают от junior/intern AQA: pytest как раннер, Allure как отчётность, фикстуры для переиспользуемого сетапа, плюс нормальная декомпозиция по слоям. В структуре это выглядит привычно: pages отвечает за страницы (Page Object), components — за компоненты (Page Component), elements — за слой элементов / Page Factory, чтобы детали локаторов и мелких UI-объектов не расползались по тестам.
В результате тесты получаются не «техническими простынями», а сценариями. Например, финальный тест регистрации выглядит так:
import allure
import pytest
from pages.dashboard_page import DashboardPage
from pages.registration_page import RegistrationPage
from tools.routes import AppRoute
@pytest.mark.regression
@pytest.mark.registration
class TestRegistration:
@allure.title("Successful registration")
def test_successful_registration(
self,
dashboard_page: DashboardPage,
registration_page: RegistrationPage
):
registration_page.visit(AppRoute.REGISTRATION)
registration_page.registration_form.check_visible(email="", username="", password="")
registration_page.registration_form.fill(
email="[email protected]",
username="Playwright",
password="qwerty"
)
registration_page.click_registration_button()
dashboard_page.navbar.check_visible("Playwright")
dashboard_page.dashboard_toolbar_view.check_visible()
dashboard_page.check_visible_scores_chart()
dashboard_page.check_visible_courses_chart()
dashboard_page.check_visible_students_chart()
dashboard_page.check_visible_activities_chart()
Это не самый большой тест в мире, но его достаточно, чтобы работодатель считал главное: вы умеете строить проект так, чтобы тесты были читаемыми, а логика взаимодействия с UI жила в страницах/компонентах, а не внутри сценария.
Отдельный сильный сигнал — когда проект не просто «лежит на GitHub», а запускается как часть процесса. В этом репозитории тесты гоняются в GitHub Actions, а результаты публикуются в виде Allure-отчёта на GitHub Pages. Это важный штрих: он показывает, что вы понимаете базовую идею CI/CD и умеете делать так, чтобы тесты давали наблюдаемый результат, а не существовали «в вакууме».
Подробный разбор того, как этот проект собирался шаг за шагом, я вынес в отдельную практическую статью: «UI автотесты на Python с запуском на CI/CD и Allure отчётом. PageObject, PageComponent, PageFactory».
API автотесты
Следующий обязательный блок в портфолио — API автотесты. На уровне рынка это выглядит просто: UI автоматизация — это полезно, но во многих командах основной объём автотестов всё равно живёт на уровне бэка. Это и дешевле в поддержке, и ближе к пирамиде тестирования, и чаще реально требуется в вакансиях. Поэтому умение тестировать API — это не «дополнительный навык», а базовая часть профиля AQA.
Важно, что от портфолио здесь ждут не “я умею делать запросы”. Делать запросы умеют все. Работодатель смотрит на другое: умеете ли вы превратить набор проверок в нормальную тестовую систему. Есть ли у тестов структура, есть ли переиспользуемость, есть ли внятное разделение ответственности между тестом, клиентом и проверками. И, как и в UI-проекте, здесь быстро видно разницу между «написал пару тестов» и «собрал поддерживаемый проект».
Чтобы было понятнее, о чём речь, вот пример того, как должен выглядеть “нормальный” API-тест в портфолио. В тесте нет сырых URL, нет логики HTTP внутри сценария, нет мешанины из ассертов — всё разложено по слоям: клиент, модели, отдельные проверки и контрактная валидация.
from http import HTTPStatus
import allure
import pytest
from clients.operations_client import OperationsClient
from schema.operations import OperationsSchema, OperationSchema, CreateOperationSchema, UpdateOperationSchema
from tools.assertions.base import assert_status_code
from tools.assertions.operations import assert_operation, assert_create_operation
from tools.assertions.schema import validate_json_schema
@pytest.mark.operations
@pytest.mark.regression
class TestOperations:
@allure.title("Get operations")
def test_get_operations(self, operations_client: OperationsClient):
response = operations_client.get_operations_api()
assert_status_code(response.status_code, HTTPStatus.OK)
validate_json_schema(response.json(), OperationsSchema.model_json_schema())
@allure.title("Get operation")
def test_get_operation(
self,
operations_client: OperationsClient,
function_operation: OperationSchema
):
response = operations_client.get_operation_api(function_operation.id)
operation = OperationSchema.model_validate_json(response.text)
assert_status_code(response.status_code, HTTPStatus.OK)
assert_operation(operation, function_operation)
validate_json_schema(response.json(), operation.model_json_schema())
@allure.title("Create operation")
def test_create_operation(self, operations_client: OperationsClient):
request = CreateOperationSchema()
response = operations_client.create_operation_api(request)
operation = OperationSchema.model_validate_json(response.text)
assert_status_code(response.status_code, HTTPStatus.CREATED)
assert_create_operation(operation, request)
validate_json_schema(response.json(), operation.model_json_schema())
@allure.title("Update operation")
def test_update_operation(
self,
operations_client: OperationsClient,
function_operation: OperationSchema
):
request = UpdateOperationSchema()
response = operations_client.update_operation_api(function_operation.id, request)
operation = OperationSchema.model_validate_json(response.text)
assert_status_code(response.status_code, HTTPStatus.OK)
assert_create_operation(operation, request)
validate_json_schema(response.json(), operation.model_json_schema())
@allure.title("Delete operation")
def test_delete_operation(
self,
operations_client: OperationsClient,
function_operation: OperationSchema
):
delete_response = operations_client.delete_operation_api(function_operation.id)
assert_status_code(delete_response.status_code, HTTPStatus.OK)
get_response = operations_client.get_operation_api(function_operation.id)
assert_status_code(get_response.status_code, HTTPStatus.NOT_FOUND)
Рассмотрим пример на реальном репозитории: https://github.com/Nikita-Filonov/python-api-tests.
Это пример API тестирования REST API на Python. В проекте нарочно собран набор практик, который хорошо читается работодателем: HTTPX как клиент, Pydantic для валидации и работы с моделями, отдельный слой API-клиента (включая base client как точку входа для всех HTTP вызовов), контрактная проверка ответов через JSON Schema, а также разделение ассертов в отдельные функции, чтобы проверки были атомарными и переиспользуемыми. Плюс — логирование, которое особенно важно в CI, и аккуратные настройки через Pydantic Settings, чтобы конфиги не превращались в хаос.
Отдельно отмечу две вещи, которые почти всегда воспринимаются как “взрослый подход”. Первая — это абстракция клиента: когда взаимодействие с API не размазано по тестам, а собрано в одном месте. Вторая — это работа с роутами через Enum вместо сырых строк. Кажется мелочью, но именно такие детали часто отличают пет-проект “для галочки” от репозитория, который не стыдно показать.
Как и в UI-блоке, сильный плюс — когда проект живёт не только локально, а встроен в минимальный процесс. Тесты гоняются в GitHub Actions, а результаты публикуются в Allure на GitHub Pages. Это снова важный сигнал: вы не просто написали тесты, а сделали так, чтобы они запускались автоматически и давали наблюдаемый результат.
Подробный разбор того, как этот проект собирался, я вынес в отдельную практическую статью: «API автотесты на Python с запуском на CI/CD и Allure отчётом».
Нагрузочные (performance) тесты
На этом месте часто возникает логичный вопрос: зачем вообще нагрузочные тесты, если мы говорим про QA Automation Engineer, а не про SRE или performance-инженера? Ответ довольно простой. Для рынка нагрузка — это не обязательное требование, но очень сильный дифференциатор. Даже если прямо сейчас в команде нет задачи делать performance-тестирование, наличие такого проекта в портфолио сразу расширяет ваш профиль.
Для работодателя это читается так: если в будущем возникнет потребность в нагрузке, здесь уже есть человек, который понимает, как это делается. Это редкий и ценный сигнал, особенно на junior–middle уровне.
Важно сразу обозначить рамку. От вас не ждут сложных моделей, математических расчётов и production SLA. В портфолио нагрузочный проект нужен не для того, чтобы “побить систему”, а чтобы показать инженерный подход: структуру, воспроизводимость, работу с данными и интеграцию в процесс.
В качестве примера можно посмотреть проект: https://github.com/Nikita-Filonov/python-load-tests
Это не демо-скрипт на 20 строк и не “hello world” Locust. Проект показывает, как может выглядеть структурированное нагрузочное тестирование REST API, которое можно запускать локально и в CI. В основе — Locust и Python, с чётким разделением слоёв: клиенты, сценарии, генерация данных, конфигурация окружения.
Ключевая идея здесь — реалистичность и повторяемость. Тестовые данные не подсовываются напрямую в базу и не мокируются, а подготавливаются через API с помощью отдельного seeding-слоя. Это важно: нагрузка должна идти по тем же бизнес-путям, что и реальный трафик, иначе она быстро теряет смысл. Сценарии при этом описываются явно и версионируются, что позволяет сравнивать результаты между запусками и не превращать тесты в одноразовый эксперимент.
Ниже небольшой фрагмент сценария, просто чтобы было понятно, о каком уровне абстракции идёт речь. Здесь видно, что нагрузка — это не “дергай эндпоинт в цикле”, а осмысленный пользовательский сценарий с подготовленными данными:
from locust import events, task
from locust.env import Environment
from seeds.builder import get_seeds_builder
from seeds.dumps import save_seeds_result
from seeds.schema.plan import SeedsPlan, SeedOperationsPlan
from seeds.schema.result import SeedOperationResult
from tools.locust.task_set import BaseLocustTaskSet
from tools.locust.user import BaseLocustUser
@events.init.add_listener
def init(environment: Environment, **kwargs):
builder = get_seeds_builder()
result = builder.build(plan=SeedsPlan(operations=SeedOperationsPlan(count=20)))
save_seeds_result(result=result, scenario="get_operations_with_seeds")
environment.seeds = result
class GetOperationTaskSet(BaseLocustTaskSet):
seed_operation: SeedOperationResult
def on_start(self) -> None:
super().on_start()
self.seed_operation = self.user.environment.seeds.get_random_operation()
@task(1)
def get_operations(self):
self.operations_client.get_operations()
@task(3)
def get_operation(self):
self.operations_client.get_operation(self.seed_operation.operation_id)
class GetOperationUser(BaseLocustUser):
tasks = [GetOperationTaskSet]
Как и в предыдущих проектах, здесь важен не только код, но и процесс. Тесты запускаются в GitHub Actions. Каждый прогон генерирует HTML-отчёт Locust, который автоматически публикуется на GitHub Pages.
Это снова про наблюдаемость и воспроизводимость. Результаты можно открыть, показать, сравнить — а не просто сказать “я что-то там гонял локально”.
Важно понимать: наличие такого проекта в портфолио не означает, что вы обязаны идти в performance. Но это сильно меняет восприятие профиля. Вы уже не выглядите как “узкий UI/API автоматизатор”, а как инженер, который понимает систему шире и умеет работать с нагрузкой, данными и CI.
Подробный разбор архитектуры и подхода я вынес в отдельную практическую статью: «Нагрузочное тестирование на Python и Locust с запуском на CI/CD».
Что не работает
В завершение важно отдельно проговорить, что часто не даёт ожидаемого эффекта при выходе на рынок.
Речь прежде всего о курсах и сертификатах с формулировками вроде «подтверждение навыков». С точки зрения работодателя такие документы почти ничего не говорят о профессиональном уровне. Они фиксируют факт прохождения программы, но не показывают, как человек думает, принимает решения и работает с реальными задачами.
Это не означает, что обучение бесполезно. Курсы могут помочь разобраться с инструментами или закрыть отдельные пробелы. Но как артефакт для первичного отбора они работают слабо и воспринимаются максимум как косвенный сигнал, что кандидат учился. Куда важнее наблюдаемые навыки — то, что можно оценить ещё до собеседования.
Часто на этом месте звучит возражение: «всё равно на собеседовании будут проверять навыки». Это так. Портфолио не заменяет интервью и не гарантирует результат.
Но цель статьи — не прохождение собеседования, а допуск к нему. Проекты нужны не для того, чтобы доказать всё, а чтобы у работодателя появился минимальный повод продолжить разговор. В этом смысле аккуратные проекты по UI, API и нагрузочному тестированию работают заметно лучше любых сертификатов: они не обещают готового специалиста, но дают понятную и проверяемую опору для решения — звать кандидата дальше или нет.
Заключение
В сухом остатке: портфолио QA — это не про количество технологий и не про сертификаты, а про понятные артефакты, по которым рынок может принять первое решение. UI, API и, при желании, нагрузочные тесты дают тот самый минимальный сигнал, который превращает резюме из набора слов в повод для разговора.
Важно уточнить одну вещь. Проекты, которые разобраны в статье, — это не «идеальные шаблоны», которые нужно копировать один в один. Их смысл в другом: показать подход, уровень абстракции и набор сигналов, которые рынок считывает как рабочий опыт. Копирование репозитория без понимания и адаптации под себя не даёт эффекта — ценится не форма, а то, как вы применяете эти идеи в собственных проектах.