Подготовка к собеседованию — QA-инженер (ручное тестирование)
Колода из 146+ карточек с вопросами для собеседования по направлению «QA-инженер (ручное тестирование)» — по темам и уровню сложности, с возвратом ровно перед тем, как вы забудете. Посмотрите несколько карточек ниже, затем войдите, чтобы учить всё направление по расписанию в стиле Anki (SM-2).
Бесплатно · вход через GitHub · ваш прогресс остаётся с вами.
Что внутри
Все темы направления, сгруппированные так, как вы будете их учить.
Базы данных
42 карточкиПоведенческое интервью
35 карточекТеория тестирования
15 карточекТехники тест-дизайна
11 карточекБаг-репорты и процессы
11 карточекHTTP, API и клиент-сервер
13 карточекВеб, мобильное и безопасность
9 карточекПрактические кейсы и задачи
10 карточекПримеры вопросов
Несколько карточек из колоды — откройте ответ, затем войдите, чтобы учить весь набор по расписанию.
Что делает SELECT и в каком порядке выполняются части запроса?
Что делает SELECT и в каком порядке выполняются части запроса?
Короткий ответ: SELECT извлекает строки из таблиц. Логический порядок выполнения НЕ совпадает с порядком написания: сначала FROM, затем WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY, LIMIT.
Подробно:
Порядок написания (синтаксический):
SELECT DISTINCT col1, agg(col2)
FROM t
WHERE cond
GROUP BY col1
HAVING agg_cond
ORDER BY col1
LIMIT 10 OFFSET 20;
Логический порядок исполнения:
1. FROM / JOIN -- какие таблицы, как соединить
2. WHERE -- фильтр строк ДО группировки
3. GROUP BY -- группировка
4. HAVING -- фильтр групп ПОСЛЕ агрегации
5. SELECT -- вычисление выражений, алиасов
6. DISTINCT -- удаление дублей
7. ORDER BY -- сортировка
8. LIMIT / OFFSET -- срез
⚠️ Ловушка: алиас из SELECT нельзя использовать в WHERE (т.к. WHERE выполняется раньше SELECT), но можно в ORDER BY и часто в GROUP BY (зависит от СУБД). Пример ошибки:
SELECT salary * 12 AS annual FROM emp WHERE annual > 100000; -- ОШИБКА
SELECT salary * 12 AS annual FROM emp ORDER BY annual; -- ОК
Чем WHERE отличается от ORDER BY, и как работают LIMIT/OFFSET?
Чем WHERE отличается от ORDER BY, и как работают LIMIT/OFFSET?
Короткий ответ: WHERE фильтрует строки, ORDER BY сортирует результат, LIMIT n OFFSET m возвращает n строк, пропустив первые m.
Подробно:
-- Пагинация: страница 3 по 20 записей (пропустить 40, взять 20)
SELECT id, name
FROM users
WHERE active = TRUE
ORDER BY created_at DESC
LIMIT 20 OFFSET 40;
⚠️ Ловушка: LIMIT без ORDER BY возвращает НЕдетерминированный набор строк — порядок не гарантирован. Также OFFSET на больших значениях медленный (СУБД всё равно читает и отбрасывает пропущенные строки) — для глубокой пагинации используйте keyset-пагинацию:
-- keyset: быстрее, чем большой OFFSET
SELECT * FROM users WHERE id > :last_seen_id ORDER BY id LIMIT 20;
Что делает DISTINCT и в чём подвох?
Что делает DISTINCT и в чём подвох?
Короткий ответ: DISTINCT убирает дублирующиеся строки из результата.
Подробно:
SELECT DISTINCT department FROM employees; -- уникальные отделы
SELECT DISTINCT department, city FROM employees; -- уникальные ПАРЫ (отдел, город)
⚠️ Ловушка: DISTINCT применяется ко ВСЕМ столбцам в SELECT, а не к одному. SELECT DISTINCT a, b ≠ «уникальные a». Также COUNT(DISTINCT col) считает уникальные значения, игnorируя NULL.
Какие бывают JOIN и чем они различаются?
Какие бывают JOIN и чем они различаются?
Короткий ответ: INNER — только совпадения; LEFT — все левые + совпадения справа (иначе NULL); RIGHT — зеркало LEFT; FULL — всё с обеих сторон; CROSS — декартово произведение; SELF — таблица с самой собой.
Подробно:
Пусть есть:
employees departments
+----+--------+----+ +----+----------+
| id | name |dept| | id | title |
+----+--------+----+ +----+----------+
| 1 | Анна | 10 | | 10 | IT |
| 2 | Борис | 20 | | 30 | Finance |
| 3 | Вера | NULL| +----+----------+
+----+--------+----+
INNER JOIN — пересечение (∩). Только строки, где есть совпадение в ОБЕИХ таблицах:
SELECT e.name, d.title
FROM employees e
INNER JOIN departments d ON e.dept = d.id;
-- Анна | IT (Борис отпал: dept 20 нет в departments;
-- Вера отпала: dept = NULL)
employees departments
[ ##### ] ← только пересечение
LEFT JOIN — все строки левой таблицы + совпадения справа (нет совпадения → NULL):
SELECT e.name, d.title
FROM employees e
LEFT JOIN departments d ON e.dept = d.id;
-- Анна | IT
-- Борис | NULL ← сохранён, departments нет
-- Вера | NULL ← сохранён, dept = NULL
[ left ##### ] ← вся левая + пересечение
RIGHT JOIN — зеркало LEFT (все строки правой):
SELECT e.name, d.title
FROM employees e
RIGHT JOIN departments d ON e.dept = d.id;
-- Анна | IT
-- NULL | Finance ← департамент 30 без сотрудников
FULL OUTER JOIN — все строки обеих таблиц:
SELECT e.name, d.title
FROM employees e
FULL OUTER JOIN departments d ON e.dept = d.id;
-- Анна | IT
-- Борис | NULL
-- Вера | NULL
-- NULL | Finance
CROSS JOIN — декартово произведение (каждая с каждой), без условия:
SELECT e.name, d.title FROM employees e CROSS JOIN departments d;
-- 3 строки × 2 строки = 6 строк
SELF JOIN — таблица к самой себе (например, сотрудник → менеджер):
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;
💡 Чем LEFT отличается от INNER на примере: если справа нет совпадения, INNER ВЫБРАСЫВАЕТ строку, а LEFT ОСТАВЛЯЕТ её, подставляя NULL в правые столбцы. Поэтому LEFT JOIN часто используют для поиска «осиротевших» записей:
-- Сотрудники без отдела
SELECT e.name
FROM employees e
LEFT JOIN departments d ON e.dept = d.id
WHERE d.id IS NULL;
⚠️ Ловушка: условие на правую таблицу в LEFT JOIN нужно класть в ON, а не в WHERE, иначе LEFT превращается в INNER:
-- НЕПРАВИЛЬНО: фильтр в WHERE отсекает строки с NULL справа → ведёт себя как INNER
SELECT e.name, d.title FROM employees e
LEFT JOIN departments d ON e.dept = d.id
WHERE d.title = 'IT';
-- ПРАВИЛЬНО: если нужно сохранить все строки слева
SELECT e.name, d.title FROM employees e
LEFT JOIN departments d ON e.dept = d.id AND d.title = 'IT';
Что такое GROUP BY и агрегатные функции?
Что такое GROUP BY и агрегатные функции?
Короткий ответ: GROUP BY группирует строки по значениям столбцов; агрегаты (COUNT, SUM, AVG, MIN, MAX) считают одно значение на группу.
Подробно:
SELECT department,
COUNT(*) AS headcount,
SUM(salary) AS payroll,
AVG(salary) AS avg_salary,
MIN(salary) AS min_salary,
MAX(salary) AS max_salary
FROM employees
GROUP BY department;
⚠️ Ловушка: в стандартном SQL в SELECT можно использовать только столбцы из GROUP BY или агрегаты. SELECT name, dept, COUNT(*) ... GROUP BY dept — ошибка (name не сгруппирован и не агрегирован). PostgreSQL это запрещает, MySQL (в нестрогом режиме) молча вернёт произвольное name.
COUNT(*) vs COUNT(col) vs COUNT(DISTINCT col) — в чём разница?
COUNT(*) vs COUNT(col) vs COUNT(DISTINCT col) — в чём разница?
Короткий ответ: COUNT(*) — все строки; COUNT(col) — строки, где col НЕ NULL; COUNT(DISTINCT col) — уникальные не-NULL значения.
Подробно:
-- Таблица: 5 строк, в phone 2 NULL, 1 дубликат
SELECT
COUNT(*) AS total, -- 5
COUNT(phone) AS with_phone, -- 3 (NULL не считаются)
COUNT(DISTINCT phone) AS unique_phones -- 2
FROM users;
⚠️ Ловушка: COUNT(col) тихо игнорирует NULL — частая причина расхождения в отчётах. Если нужно посчитать все строки — всегда COUNT(*).
Готовы закрепить навсегда?
Первая сессия — меньше минуты. Ваше будущее «я» на собеседовании скажет спасибо.