Этапы разработки:
Используя подход shift-left testing, на этом этапе QA подключаются к анализу требований. Что б минимизировать затраты на фиксы ошибок. Для этого, когда требования будут собраны, но не зафиксированы, надо назначить встречу всей команды, что б каждый член команды мог проанализировать требования и уточнить непонятные моменты. Аналитик должен посвятить команду в тонкости техническую часть требований, а ПМ должен погрузить команду в бизнес процесс. Тогда QA смогут выделить критичные сценарии для бизнеса и в дальнейшем грамотнее выстраивать тестирование и тест дизайн. Так же на этой встрече могут быть заблаговременно выявлены логические, бизнесовые или технические ошибки в требованиях. Что значительно удешевит и ускорит их исправление. Так же по существующей аналитике пишутся чек листы, по которым в дальнейшем будут писаться тест кейсы. Пишется план тестирования в котором прописываются сроки, человекочасы, инструменты тестирования итд.
На данном этапе привлекаются опытные QA, которые могут знать особенности уже имеющейся архитектуры. Слабые места итд. Т.к. QA владеют довольно большими знаниями о проекте в целом, то они могут помочь указать на места где может быть высокая нагрузка на сервис. Может где то нелогично часто приходится ходить в разные БД для формирования простого запроса. Такие моменты могут подсветить опытные QA. Так же обсуждаются инструменты для выстраивания грамотного CI\CD. Что б QA и разработка были на одной волне.
На этапе разработки QA приступают к написанию тестовой модели. Применяя техники тест дизайна :
- Предугадывание ошибки
- Таблица принятия решений
- Попарное тестирование
- Анализ граничных значений
- Классы эквивалентности
Создаются тестовые наборы API тесты, Интеграционные тесты, UI тесты, Е2Е. В API тестах пишется больше всего тестов. Пишутся контрактные тесты на проверку маппинга и валидацию посылаемых и запрашиваемых данных. В Интеграционных тестах пишутся тесты интеграций микросервисов друг с другом. Микросервисов с БД. UI части с бэкендом. В UI тестах пишутся тесты на проверку всех UI элементов на всех экранах во всем флоу. В Е2Е пишутся сквозные тесты, которые проходят по основному пользовательскому пути и проверяют, что весь сценарий работает целиком. Проверяются интеграции всего процесса, логи, метрики, записи\выгрузки БД и UI часть. Заводятся остальные артефакты релиза. Подготавливается рыба отчета по тестированию. Заводится релиз. Уточняются сроки. Проводится настройка тестового стенда и подготовка тестовых данных. Выстраивание метрик тестирования. На первом релизе важно покрыть как можно больше требований кейсами. Так что будем руководствоваться метрикой тестового покрытия требований что б понять. Т.к. ПО связанно с покупками, то нам важно не иметь критичных и серьезных багов. Поэтому за Quality Gate будем брать отсутствие критичных и серьезных багов. Допустимы тривиальные баги с низким приоритетом (не более 3 штук), которые попадают в техдолг и обязаны быть исправлены в следующем релизе\хотфиксе. При получении промежуточных билдов, надо проверять интеграции, особенно внешние. Что б успеть отладиться к этапу тестирования.
На данном этапе проводится само тестирование. При получении сборки со всеми разработанными фичами, надо провести Smoke тестирование для проверки работоспособности всей системы. Следующей проверкой должен быть Critical path, что б проверить главный бизнесовый путь клиента. Далее проводятся позитивные проверки критичного для бизнеса функционала. Дальше если нигде не заблокированы, то более опытные QA подключаются к проверкам E2E и интеграционных проверок. Менее опытные коллеги могут проверить маппинг в контрактных тестах API и экраны в UI. Так же есть активность по заведению и актуализации багов. После успешного фикса багов заводится и проходится тестовый прогон с регрессионными кейсами. Итогом тестирования является отчет о тестировании в котором указаны сроки тестирования, кто и что тестировал. Линкуются прогоны с пройденными тест кейсами и баги, как пофикшенные, так и пропущенные в релиз. Так же пишутся рекомендации по улучшению качества на следующей итерации.
(Ресурсы: 2-3 QA Лучше пусть будет в запасе 1 человек, ибо первый запуск и нет понимания слабых мест и с какими трудностями придется столкнуться в ходе тестирования Сроки: 4-5 недели с запасом.)
На данном этапе происходит поддержка приложения. Происходит мониторинг действий пользователей. Сбор метрик, построение воронки. Анализ нагрузки и стабильности. Получение и разбор багов от 1-й линии поддержки и выкатка хотфиксов. Проведение регрессионного тестирования после каждого хотфикса.
-- Создание БД academy
CREATE DATABASE academy;
-- Добавление таблиц
CREATE TABLE Students (
s_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
start_year INTEGER NOT NULL
);
CREATE TABLE Courses (
c_no SERIAL PRIMARY KEY,
title VARCHAR(100) NOT NULL,
hours INTEGER NOT NULL
);
CREATE TABLE Exams (
s_id INTEGER NOT NULL,
c_no INTEGER NOT NULL,
score INTEGER NOT NULL,
FOREIGN KEY (s_id) REFERENCES Students(s_id),
FOREIGN KEY (c_no) REFERENCES Courses(c_no)
);
-- Добавление нескольких записей в таблицы
INSERT INTO Students (name, start_year) VALUES ('Иван Иванов', 2020);
INSERT INTO Students (name, start_year) VALUES ('Мария Петрова', 2019);
INSERT INTO Students (name, start_year) VALUES ('Орк Мамонтов', 2015);
INSERT INTO Students (name, start_year) VALUES ('Евпатий Орлов', 2018);
INSERT INTO Students (name, start_year) VALUES ('Лютик Лютый', 2013);
INSERT INTO Students (name, start_year) VALUES ('Лев Львович', 2012);
INSERT INTO Students (name, start_year) VALUES ('Дир Диров', 2018);
INSERT INTO Courses (title, hours) VALUES ('Математика', 60);
INSERT INTO Courses (title, hours) VALUES ('История', 45);
INSERT INTO Courses (title, hours) VALUES ('Физика', 50);
INSERT INTO Courses (title, hours) VALUES ('Астрономия', 55);
INSERT INTO Courses (title, hours) VALUES ('Русский', 70);
INSERT INTO Courses (title, hours) VALUES ('Химия', 88);
INSERT INTO Exams (s_id, c_no, score)
SELECT s.s_id, c.c_no, FLOOR(50 + RANDOM() * 51)
FROM Students s, Courses c;
-- Запрос, который возвращает всех студентов, которые еще не сдали ни одного экзамена.
SELECT s.name
FROM Students s
LEFT JOIN Exams e ON s.s_id = e.s_id
WHERE e.s_id IS NULL;
-- Запрос, который возвращает список студентов и количество сданных им экзаменов. Только для студентов, у которых есть сданные экзамены.
SELECT s.name, COUNT(e.s_id) AS passed_exams_count
FROM Students s
JOIN Exams e ON s.s_id = e.s_id
GROUP BY s.name
HAVING COUNT(e.s_id) > 0;
-- Вывод список курсов со средним баллом по экзамену. Список отсортирован по убыванию среднего балла.
SELECT c.title, AVG(e.score) AS average_score
FROM Courses c
JOIN Exams e ON c.c_no = e.c_no
GROUP BY c.title
ORDER BY average_score DESC;
-- Скрипт, который наполняет таблицы произвольными данными
-- Функция для генерации случайных имен студентов
CREATE OR REPLACE FUNCTION random_name() RETURNS TEXT AS $$
DECLARE
names TEXT[] = ARRAY['Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Helen', 'Ivan', 'Julia'];
BEGIN
RETURN names[1 + floor(random() * array_length(names, 1))];
END;
$$ LANGUAGE plpgsql;
-- Функция для генерации случайных названий курсов
CREATE OR REPLACE FUNCTION random_title() RETURNS TEXT AS $$
DECLARE
titles TEXT[] = ARRAY['Math', 'Physics', 'Chemistry', 'Biology', 'History', 'Geography', 'English', 'French', 'Spanish', 'German'];
BEGIN
RETURN titles[1 + floor(random() * array_length(titles, 1))];
END;
$$ LANGUAGE plpgsql;
-- Заполнение таблицы Students случайными данными
INSERT INTO Students (name, start_year)
SELECT random_name(), 2000 + floor(random() * 20)
FROM generate_series(1, 100);
-- Заполнение таблицы Courses случайными данными
INSERT INTO Courses (title, hours)
SELECT random_title(), 1 + floor(random() * 100)
FROM generate_series(1, 50);
-- Заполнение таблицы Exams случайными данными
INSERT INTO Exams (s_id, c_no, score)
SELECT s.s_id, c.c_no, 1 + floor(random() * 100)
FROM generate_series(1, 1000) AS gs,
(SELECT s_id FROM Students ORDER BY random() LIMIT 100) AS s,
(SELECT c_no FROM Courses ORDER BY random() LIMIT 50) AS c;
-- Удаление временных функций
DROP FUNCTION random_name();
DROP FUNCTION random_title();