Bash-скриптинг для QA
Updated Jul 2026
Почему QA-инженеры пишут скрипты
Bash-скрипты автоматизируют повторяющиеся QA-задачи: проверка здоровья окружений, подготовка тестовых данных, запуск дымовых тестов, анализ логов и управление тестовой инфраструктурой. Хорошо написанный скрипт экономит часы ручной работы и снижает вероятность человеческой ошибки.
Основы Bash
Структура скрипта
#!/bin/bash
# Строка shebang (первая строка) указывает системе использовать bash
# Немедленный выход при ошибке команды
set -e
# Считать неустановленные переменные ошибкой
set -u
# Ошибка при сбое в конвейере (не только последней команды)
set -o pipefail
# Здесь идёт логика вашего скрипта
echo "Script started at $(date)"
Сделайте скрипт исполняемым: chmod +x my-script.sh
Запуск скрипта: ./my-script.sh или bash my-script.sh
Переменные
# Присвоение (без пробелов вокруг =)
NAME="QA Engineer"
PORT=3000
BASE_URL="https://staging.example.com"
# Использование переменных
echo "Hello, $NAME"
echo "Server is at ${BASE_URL}:${PORT}"
# Значения по умолчанию (использовать умолчание, если переменная не установлена)
TIMEOUT=${TEST_TIMEOUT:-30000}
BROWSER=${TEST_BROWSER:-chromium}
# Подстановка команды (захват вывода команды в переменную)
CURRENT_DATE=$(date +%Y-%m-%d)
GIT_HASH=$(git rev-parse --short HEAD)
Массивы
# Объявление массива
ENVIRONMENTS=("dev" "staging" "preprod")
BROWSERS=("chromium" "firefox" "webkit")
# Доступ к элементам
echo "${ENVIRONMENTS[0]}" # Первый элемент: "dev"
echo "${ENVIRONMENTS[@]}" # Все элементы
echo "${#ENVIRONMENTS[@]}" # Количество: 3
# Итерация по массиву
for env in "${ENVIRONMENTS[@]}"; do
echo "Testing $env..."
done
Управление потоком выполнения
Условные конструкции
# If/else
if [ "$STATUS" -eq 200 ]; then
echo "PASS: Service is healthy"
elif [ "$STATUS" -eq 503 ]; then
echo "WARNING: Service unavailable"
else
echo "FAIL: Unexpected status $STATUS"
fi
# Сравнение строк
if [ "$ENVIRONMENT" = "production" ]; then
echo "Running production smoke tests"
fi
# Проверка файлов
if [ -f "test-config.json" ]; then
echo "Config file exists"
fi
if [ -d "test-results" ]; then
echo "Results directory exists"
fi
# Логические операторы
if [ "$STATUS" -eq 200 ] && [ "$RESPONSE_TIME" -lt 5 ]; then
echo "Fast and healthy"
fi
Часто используемые операторы проверки
| Оператор | Значение | Пример |
|---|---|---|
-eq |
Равно (числовое) | [ "$a" -eq 200 ] |
-ne |
Не равно (числовое) | [ "$a" -ne 0 ] |
-lt |
Меньше | [ "$a" -lt 100 ] |
-gt |
Больше | [ "$a" -gt 0 ] |
= |
Равно (строковое) | [ "$a" = "hello" ] |
!= |
Не равно (строковое) | [ "$a" != "" ] |
-f |
Файл существует | [ -f "config.json" ] |
-d |
Каталог существует | [ -d "results/" ] |
-z |
Строка пустая | [ -z "$VAR" ] |
-n |
Строка не пустая | [ -n "$VAR" ] |
Циклы
# Цикл for со списком
for browser in chromium firefox webkit; do
echo "Running tests in $browser"
npx playwright test --project="$browser"
done
# Цикл for с диапазоном
for i in $(seq 1 5); do
echo "Test run $i of 5"
done
# Цикл while
ATTEMPTS=0
MAX_ATTEMPTS=10
while [ "$ATTEMPTS" -lt "$MAX_ATTEMPTS" ]; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/health")
if [ "$STATUS" -eq 200 ]; then
echo "Service is up after $ATTEMPTS attempts"
break
fi
ATTEMPTS=$((ATTEMPTS + 1))
sleep 5
done
Функции
# Определение функции
check_health() {
local env=$1
local url="https://${env}.example.com/health"
local status
status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "$url")
if [ "$status" -eq 200 ]; then
echo "PASS: $env ($status)"
return 0
else
echo "FAIL: $env ($status)"
return 1
fi
}
# Вызов функции
check_health "staging"
check_health "production"
Практический скрипт: дымовое тестирование нескольких окружений
#!/bin/bash
# run-smoke-tests.sh -- Health-check multiple environments
set -euo pipefail
ENVIRONMENTS=("dev" "staging" "preprod")
FAIL_COUNT=0
RESULTS=()
check_health() {
local env=$1
local url="https://${env}.example.com/health"
local status
local time
status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "$url" 2>/dev/null || echo "000")
time=$(curl -s -o /dev/null -w "%{time_total}" --max-time 30 "$url" 2>/dev/null || echo "0")
if [ "$status" -eq 200 ]; then
RESULTS+=("PASS: $env (HTTP $status, ${time}s)")
return 0
else
RESULTS+=("FAIL: $env (HTTP $status, ${time}s)")
return 1
fi
}
echo "=== Environment Health Check ==="
echo "Date: $(date)"
echo "================================"
for env in "${ENVIRONMENTS[@]}"; do
check_health "$env" || FAIL_COUNT=$((FAIL_COUNT + 1))
done
echo ""
for result in "${RESULTS[@]}"; do
echo " $result"
done
echo ""
echo "Results: $((${#ENVIRONMENTS[@]} - FAIL_COUNT))/${#ENVIRONMENTS[@]} passed"
if [ "$FAIL_COUNT" -gt 0 ]; then
echo "STATUS: SOME ENVIRONMENTS DOWN"
exit 1
else
echo "STATUS: ALL ENVIRONMENTS HEALTHY"
exit 0
fi
Практический скрипт: ожидание готовности сервиса
#!/bin/bash
# wait-for-service.sh -- Wait until a service is ready before running tests
set -euo pipefail
URL="${1:?Usage: $0 <url> [timeout_seconds]}"
TIMEOUT="${2:-120}"
INTERVAL=5
ELAPSED=0
echo "Waiting for $URL to be ready (timeout: ${TIMEOUT}s)..."
while [ "$ELAPSED" -lt "$TIMEOUT" ]; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$URL" 2>/dev/null || echo "000")
if [ "$STATUS" -eq 200 ]; then
echo "Service is ready (HTTP $STATUS) after ${ELAPSED}s"
exit 0
fi
echo " Not ready (HTTP $STATUS), retrying in ${INTERVAL}s... (${ELAPSED}/${TIMEOUT}s)"
sleep "$INTERVAL"
ELAPSED=$((ELAPSED + INTERVAL))
done
echo "ERROR: Service not ready after ${TIMEOUT}s"
exit 1
Использование: ./wait-for-service.sh https://staging.example.com/health 180
Практический скрипт: очистка тестовых данных
#!/bin/bash
# cleanup-test-data.sh -- Remove test data older than N days
set -euo pipefail
DAYS="${1:-7}"
DIRS=("test-results" "screenshots" "videos" "traces" "coverage")
echo "Cleaning up test artifacts older than $DAYS days..."
for dir in "${DIRS[@]}"; do
if [ -d "$dir" ]; then
COUNT=$(find "$dir" -type f -mtime +"$DAYS" | wc -l)
if [ "$COUNT" -gt 0 ]; then
echo " Removing $COUNT files from $dir/"
find "$dir" -type f -mtime +"$DAYS" -delete
else
echo " $dir/ -- nothing to clean"
fi
fi
done
echo "Cleanup complete"
Обработка ошибок в скриптах
# Перехват ошибок и очистка
cleanup() {
echo "Cleaning up..."
docker compose down -v 2>/dev/null || true
rm -f /tmp/test-data-*.json
}
# Вызвать cleanup при выходе (успех или ошибка)
trap cleanup EXIT
# Вызвать cleanup при определённых сигналах
trap cleanup SIGINT SIGTERM
Лучшие практики скриптинга
| Практика | Зачем |
|---|---|
Используйте set -euo pipefail |
Ловить ошибки рано, а не продолжать молча |
Используйте local в функциях |
Предотвращать утечку переменных между функциями |
| Оборачивайте все переменные в кавычки | Предотвращать разбиение слов: "$VAR", а не $VAR |
Используйте shellcheck |
Инструмент статического анализа для обнаружения типичных ошибок bash |
| Добавляйте сообщения об использовании | echo "Usage: $0 <url> [timeout]" |
| Используйте осмысленные коды возврата | 0 = успех, 1 = ошибка, 2 = ошибка использования |
| Комментируйте неочевидную логику | Будущий вы будет благодарен настоящему вам |
Практическое упражнение
- Напишите скрипт дымового тестирования, который проверяет 3 URL и выводит результаты пройдено/не пройдено
- Напишите скрипт ожидания готовности сервиса и используйте его перед запуском тестового набора
- Напишите скрипт очистки, удаляющий артефакты тестов старше 7 дней
- Установите
shellcheckи проверьте им ваши скрипты. Исправьте все предупреждения. - Добавьте обработку ошибок (trap) в один из ваших скриптов
- Напишите скрипт, который принимает имя окружения как аргумент и запускает соответствующий набор тестов