testing-aqa: вопросы с ответами
61 разобранных вопросов по теме «testing-aqa». Каждый — с правильным ответом и пояснением.
- Что такое ArgumentCaptor?
Захват аргумента: verify(repo).save(captor.capture()); assertThat(captor.getValue().getName()).isEqualTo("Alice"). Когда нужно проверить не факт вызова, а конкретные значения.
- ArgumentCaptor — зачем нужен?
Захват аргумента, переданного в замоканный метод. verify(service).send(captor.capture()); assertThat(captor.getValue().getEmail()).isEqualTo("test@mts.ru"). Для AQA: проверить, что в мок реально передали ожидаемые значения полей — captor захватывает входной аргумент, а конкретные поля проверяются явными assert'ами.
- В чём разница: AssertJ vs Hamcrest?
AssertJ — fluent API (assertThat(x).isEqualTo(y).hasSize(3)), более читаемый, богаче. Hamcrest — matchers (assertThat(x, equalTo(y))). В вакансии Лиги оба.
- @BeforeAll и @AfterAll — что важно?
В JUnit 5 они должны быть static (или класс аннотирован @TestInstance(Lifecycle.PER_CLASS)).
- Что такое Black Box / White Box / Grey Box?
Black Box: не знаем внутреннюю реализацию, тестируем по спецификации. White Box: знаем код, тестируем ветвления, покрытие. Grey Box: знаем архитектуру, сочетаем оба подхода.
- Decision Table — когда применять?
Когда поведение зависит от комбинации условий. Пример: кредит одобряется если (доход > 50к) И (кредитная история хорошая) И (возраст 21–65) — таблица перечисляет все сочетания условий и ожидаемое действие для каждого.
- End-to-End тест — что это?
Тест полного пользовательского сценария от начала до конца. Пример: регистрация → логин → создание заявки → одобрение → выдача кредита → погашение. Проходит через все слои: UI/API → бэкенд → БД → Kafka → внешние сервисы, проверяя функциональную корректность всего пути.
- В чём разница: Hard assertions vs Soft assertions?
Hard (по умолчанию): при первом провале тест падает, остальные проверки не выполняются. Soft (assertAll в JUnit 5, SoftAssertions в AssertJ): все проверки выполняются, ошибки собираются и сообщаются разом, но при наличии хотя бы одной тест всё равно падает.
- IDOR — что это?
Insecure Direct Object Reference: один клиент видит данные другого. GET /api/users/123/accounts — если проверки прав нет, можно подставить чужой ID и увидеть чужие счета. Как тестировать: авторизоваться под user A и обратиться к ресурсам user B.
- JSON Schema validation — зачем?
Проверяет структуру ответа (типы полей, обязательные поля, формат): body(matchesJsonSchemaInClasspath("schemas/user.json")). Защищает тест от непредвиденных изменений API-контракта.
- JSONPath — как извлекать данные?
$.user.id — поле id объекта user. $..items[*].name — все name из массива items. $..items[?(@.price > 100)] — фильтрация. В Rest Assured: .extract().path("user.id"). Для валидации: body("user.name", equalTo("Alice")).
- JUnit 5: основные аннотации?
@Test — тестовый метод. @BeforeEach/@AfterEach — до/после каждого теста. @BeforeAll/@AfterAll — до/после всех (static). @DisplayName — читаемое имя. @Disabled — пропустить. @Tag — категория (smoke, regression).
- В чём разница: mock vs spy?
mock() — пустой объект, всё default. spy() — обёртка над реальным: методы вызываются, если не замокать. Для spy: doReturn().when(spy).method() (иначе вызовется реальный метод).
- В чём разница: Mockito: mock vs spy?
mock() — пустой объект, все методы возвращают default (null, 0, false). spy() — обёртка над реальным объектом, методы вызываются по-настоящему, если не заmock'ать.
- Mockito: Mock vs Spy — в чём разница?
Mock: полностью пустой объект, все методы возвращают default (null, 0, false). Spy: обёртка над реальным объектом, методы вызываются по-настоящему, если не замоканы. Для Spy нужно писать doReturn().when(spy).method(), а не when(spy.method()).thenReturn(...), потому что when(spy.method()) сначала реально вызовет метод.
- Pairwise testing — зачем?
Когда параметров много (5 полей по 4 значения = 1024 комбинации). Pairwise: покрыть все ПАРЫ параметров (не все комбинации). Инструменты: PICT (Microsoft), AllPairs. Сокращает количество тестов с 1024 до ~20, покрывая 80% багов.
- PCI DSS — что должен знать AQA?
Payment Card Industry Data Security Standard. CVV/CVC нельзя хранить вообще (даже в зашифрованном виде) после авторизации. Номер карты (PAN) при хранении должен быть нечитаемым — только маскированный (****1234), токенизированный или зашифрованный. Логи не должны содержать полный PAN.
- Что такое PriorityQueue?
Min-heap по умолчанию. O(log n) offer/poll, O(1) peek. Для Top-K задач. Comparator для кастомного порядка.
- В чём разница: QA vs QC?
QA (Quality Assurance): процесс обеспечения качества — стандарты, процессы, предотвращение дефектов. QC (Quality Control): контроль качества — тестирование, нахождение дефектов. QA — шире, QC — часть QA.
- Scrum церемонии: Planning, Daily, Review, Retro?
Planning: что берём в спринт, декомпозиция. Daily: 15 мин, три вопроса (что сделал, что буду, что блокирует) — синхронизация команды, а не отчёт менеджеру. Review: демо инкремента стейкхолдерам. Retrospective: что было хорошо, что улучшить, action items — про процесс, а не про продукт.
- В чём разница: Severity vs Priority?
Severity: техническая серьёзность (Critical/Major/Minor/Trivial). Priority: бизнес-важность и срочность исправления (High/Medium/Low). Они независимы: например, Critical + Low = баг критичный, но в третьестепенной фиче, которой почти не пользуются, — и наоборот.
- Smoke / Sanity / Regression / Confirmation — отличия?
Smoke: «дымовой тест» — базовая работоспособность после деплоя (5–10 кейсов). Sanity: проверка конкретного фикса/фичи (узко). Regression: проверка, что старое не сломалось (широко, автоматизируем). Confirmation (retest): повторная проверка, что именно тот баг действительно исправлен.
- State Transition — как использовать?
Для систем с состояниями: заявка на кредит (Новая → На рассмотрении → Одобрена/Отклонена → Выдана). Рисуем диаграмму состояний и переходов. Тестируем: все валидные переходы + невалидные (из «Выдана» нельзя в «Новая»).
- В чём разница: Stub vs Verify в WireMock?
Stub: настроить фиксированный ответ — stubFor(get("/api/rates").willReturn(okJson(...))). Verify: проверить, что наш сервис сделал ожидаемый запрос — verify(getRequestedFor(urlEqualTo("/api/rates"))). Это разные фазы: настройка vs проверка.
- Что нужно знать про TDD?
Red: падающий тест. Green: минимальный код. Refactor: улучшаем без изменения поведения. Private-методы не тестируем — через публичные. Если сложно — выдели класс.
- Что такое Testcontainers?
Реальные БД/Kafka в Docker из тестов. @Testcontainers + @Container PostgreSQLContainer. Зачем: тесты на реальной PostgreSQL, а не H2 (которая отличается). Проверка миграций Flyway, SQL, Kafka-consumers.
- Testcontainers — что это?
Библиотека для запуска Docker-контейнеров из Java-тестов. PostgreSQLContainer, KafkaContainer, GenericContainer (WireMock). @Testcontainers + @Container. Для AQA: поднять реальную БД вместо H2. Контейнеры поднимаются и останавливаются программно.
- verify — что это и зачем?
Проверка, что метод был вызван (сколько раз, с какими аргументами). verify(mock, times(2)).method(anyString()).
- В чём разница: when/thenReturn vs doReturn/when?
when(x.method()).thenReturn(y) — стандартный способ. doReturn(y).when(x).method() — нужен для spy (иначе вызовется реальный метод) и для void-методов.
- Что такое WireMock?
Мок HTTP-сервисов для интеграционных тестов. WireMockServer или @WireMockTest. stubFor(get("/api/...").willReturn(okJson("..."))). Позволяет тестировать взаимодействие с внешними API без реального вызова.
- WireMock — зачем нужен?
Заглушка для внешних сервисов. Вместо реального API курсов валют — мок с фиксированным ответом. Преимущества: тесты не зависят от внешнего сервиса, можно имитировать ошибки (500, таймаут), детерминированные данные.
- Базовый набор Mockito?
@Mock — создать мок. @InjectMocks — создать тестируемый объект и подставить в него моки. @ExtendWith(MockitoExtension.class) — активировать. when(mock.method(...)).thenReturn(...) — задать поведение. verify(mock).method(...) — проверить, что метод был вызван.
- В чём разница Mock и Spy?
Mock — полная имитация, по умолчанию все методы возвращают null / 0 / false, поведение задаёшь через when().thenReturn(). Spy — обёртка над реальным объектом: методы, которые ты не подменил, выполняют настоящую логику. Полезно, когда нужно оставить реальное поведение объекта и заглушить лишь отдельные методы.
- В чём разница: Верификация vs Валидация?
Верификация: «Строим ли мы продукт правильно?» — соответствие требованиям, обычно статическими методами (ревью, инспекции, статический анализ). Валидация: «Строим ли мы правильный продукт?» — соответствие ожиданиям пользователя, обычно тестированием на реальных сценариях использования.
- Где брать тестовые данные в банке?
Продовые данные нельзя — персональные данные (152-ФЗ). Варианты: 1) Синтетические генераторы (JavaFaker, DataFactory). 2) Маскированный прод (замена ФИО, телефонов, номеров карт). 3) Фикстуры в тестах (@BeforeEach). Закон о персональных данных распространяется и на тестовые среды, поэтому обезличивание обязательно.
- Главный плюс constructor injection в тестах?
Не нужен Spring-контекст для юнит-теста. Просто new MyService(mock1, mock2) — и можно тестировать. Контекст Spring поднимается секунды-десятки секунд, на тысячах юнит-тестов это разница в часы CI.
- Граничные значения — почему важны?
Баги чаще всего на границах: 0, 1, max, max+1. Пример: пароль 8–20 символов → тестируем: 7 (отказ), 8 (ок), 20 (ок), 21 (отказ). Для Junior: уметь определять границы для любого поля.
- Что такое Жизненный цикл бага?
New → Open → Assigned → In Progress → Fixed → Resolved → Verified → Closed (или Reopen при неудачной проверке). Severity: Blocker (блокирует работу), Critical (потеря денег), Major (основной сценарий с workaround), Minor (косметика). Severity и Priority независимы, а верификацию и закрытие делает тестировщик.
- Зачем писать тесты?
(1) Защита от регресса — поменял код, прогнал тесты, увидел что сломалось. (2) Документация — тест показывает, как код должен использоваться. (3) Дизайн — код, который сложно тестировать, обычно плохо спроектирован. При этом зелёные тесты доказывают наличие ошибок, а не их отсутствие.
- Какие assertions используются?
assertEquals(expected, actual) — равенство через equals() (первым идёт ожидаемое, потом фактическое). assertTrue / assertFalse — для boolean. assertNotNull / assertNull. assertThrows(Exception.class, () -> ...) — проверка, что код бросает исключение. Ссылочную идентичность проверяет assertSame.
- Какие базовые аннотации JUnit 5?
@Test — обозначает тестовый метод. @BeforeEach / @AfterEach — выполняется перед/после каждого теста. @BeforeAll / @AfterAll — один раз перед/после всех тестов класса (метод должен быть static).
- Какие виды тестов бывают?
Unit (юнит) — проверяет один класс или метод изолированно, зависимости замокированы. Быстро, много, легко отлаживать. Integration — проверяет взаимодействие нескольких компонентов, часто с реальной БД. E2E — прогоняет сценарий через всю систему целиком.
- Классы эквивалентности — как применять?
Разбиваем входные данные на группы, в которых поведение системы одинаковое, и берём по одному представителю из каждой группы. Пример: поле «возраст» 18–60 → три класса: <18 (отказ), 18–60 (принимаем), >60 (отказ) — этим резко сокращаем число тестов.
- Когда TDD не работает?
Исследовательский код (прототипы), UI-разработка, GUI, задачи где требования постоянно меняются в процессе.
- Что такое Параметризация тестов в JUnit 5?
@ParameterizedTest + источник данных: @ValueSource(strings = {"a", "b"}), @CsvSource({"1, true", "2, false"}), @MethodSource("dataProvider"), @CsvFileSource(resources = "/data.csv"). Для AQA: параметризация status-кодов и наборов входных данных, чтобы прогнать один тест на множестве значений.
- Что такое Пирамида тестирования?
Unit (много, быстро) → интеграционные (связь компонентов) → e2e (мало, хрупко). В банках: обязательно unit + integration. E2e — на критичных сценариях.
- В чём разница: Позитивное vs негативное тестирование?
Позитивное: проверяем штатное поведение (валидные данные → ожидаемый результат). Негативное: проверяем реакцию на невалидные данные (пустое поле, отрицательная сумма, SQL-инъекция → ожидаем контролируемую ошибку, а не падение).
- Что такое Принципы тестирования?
Полное тестирование невозможно. Кластеризация дефектов (80% багов в 20% модулей). Парадокс пестицида (одни тесты перестают находить баги — обновляй). Раннее тестирование дешевле. Отсутствие ошибок — заблуждение (найденных багов нет ≠ проблем нет).
- Что такое Структура тест-кейса?
ID, заголовок (что тестируем), предусловие (авторизован, баланс > 0), шаги (1. POST /payment..., 2. GET /status...), ожидаемый результат (статус 200, баланс уменьшился), постусловие (откатить данные). Именно ожидаемый результат отличает тест-кейс от простого описания действий.
- Что такое Структура теста Rest Assured?
given() — настройка запроса (headers, body, params). when() — HTTP-метод + URL. then() — проверки (statusCode, body). extract() — извлечение данных из ответа. Это BDD-стиль с фиксированным порядком этапов.
- В чём разница: Тест-кейс vs чек-лист?
Тест-кейс: подробный (шаги, ожидаемый результат, предусловия) — для критичных сценариев, передачи другим. Чек-лист: краткий список проверок без деталей — для опытных, быстрой проверки. В автоматизации: тест-кейс → метод с @Test.
- Что такое Тестирование авторизации?
Без токена → 401. С истёкшим токеном → 401. С токеном другого пользователя → 403. С битым токеном → 401. С правильным токеном → 200. Double submit: дважды нажать «Оплатить» → должно списать один раз (идемпотентность). 401 — не аутентифицирован, 403 — нет прав.
- Тестировать ли private методы?
Нет — тестируются через публичные. Если private стало сложно — это сигнал, что надо выделить отдельный класс.
- Что такое Уровни тестирования?
Unit → Integration → System → Acceptance. Unit: отдельный метод/класс (JUnit, Mockito). Integration: взаимодействие компонентов (Testcontainers, WireMock). System: вся система целиком. Acceptance: приёмка пользователем (UAT).
- Что такое Цепочка запросов в Postman?
1) POST /auth/login → получить accessToken. 2) В Tests: pm.environment.set("token", jsonData.accessToken). 3) GET /users/me с заголовком Authorization: Bearer {{token}}. 4) Проверка: pm.expect(pm.response.code).to.equal(200).
- Что делать, если разработчик говорит «не баг, а фича»?
1) Проверить требования — ссылка на спецификацию. 2) Если требований нет — эскалировать на PO/аналитика. 3) Оформить баг с чётким ОР/ФР и приложить доказательства. 4) Обсудить на daily/grooming. Спор решается не авторитетом, а требованиями.
- Что такое Mockito?
Библиотека для создания моков (имитаций) объектов в тестах. Позволяет «подменить» зависимость тестируемого класса фейком, который ведёт себя так, как тебе нужно.
- Что такое TDD?
Red-Green-Refactor. Сначала пишешь падающий тест (Red), потом минимальный код чтобы он прошёл (Green), потом рефакторишь без изменения поведения.
- Что такое Testcontainers?
Библиотека для запуска реальных БД/брокеров в Docker из тестов. Нужна для интеграционных тестов, которые проверяют реальную работу с PostgreSQL/Kafka, а не моки.
- Что такое фикстура в тестах?
Подготовка фиксированного окружения и данных перед тестом. @BeforeEach: создать пользователя, залить данные в БД. @AfterEach: удалить данные. Builder/Factory для создания тестовых объектов.
- API-тесты на Rest Assured дублируют baseUrl, headers и auth в каждом тесте. Что лучше сделать?
Вынести общую RequestSpecification и переиспользовать её в тестах.