> Писал ли юнит-тесты для bash-скриптов (Go)
Уровень: middle · Роль: backend · Категория: Технические вопросы
Компании: Wildberries
Стек: Go
> Пример ответа
Короткий ответ
Да, писал. Для bash-скриптов использовал Bats (Bash Automated Testing System) и shellcheck для статического анализа. Основной фокус - тестирование логики скриптов: обработка аргументов, exit codes, работа с файлами и переменными окружения. В Go-проектах bash-скрипты обычно покрывают CI-задачи, миграции или деплой, поэтому тесты писал для критичных сценариев, а не для всего подряд.
Подробное объяснение
Bash-скрипты в Go-проектах чаще всего выполняют вспомогательные функции: сборка, запуск тестов, генерация кода, работа с Docker. Тестировать их нужно, потому что ошибка в таком скрипте может сломать CI или деплой.
Основные подходы:
- Bats - фреймворк для юнит-тестов bash. Позволяет писать тесты в стиле TAP (Test Anything Protocol), проверять stdout/stderr, exit codes.
- shellcheck - не тесты, но обязательный инструмент для статического анализа. Ловит синтаксические ошибки, неиспользуемые переменные, проблемы с quoting.
- mock-зависимости - если скрипт вызывает внешние команды (docker, git, curl), их можно замокать через
PATHили функции-заглушки. - тестирование через
set -euo pipefail- это не тест, но помогает сделать скрипт предсказуемым и тестируемым.
Пример структуры:
BASH#!/usr/bin/env batssetup() {export TEST_DIR=$(mktemp -d)}teardown() {rm -rf "$TEST_DIR"}@test "скрипт возвращает 0 при успешном выполнении" {run ./deploy.sh --dry-run[ "$status" -eq 0 ]}@test "скрипт обрабатывает отсутствие аргумента" {run ./deploy.sh[ "$status" -ne 0 ][[ "$output" =~ "usage:" ]]}
На практике
В реальных Go-проектах я покрывал тестами:
- скрипты миграций БД (проверка порядка выполнения, идемпотентность);
- скрипты генерации кода (protoc, swagger);
- CI-скрипты (проверка, что скрипт корректно обрабатывает отсутствие переменных окружения);
- скрипты деплоя (dry-run режим, проверка валидности конфигов).
Важный момент - не тестировать сам bash, а тестировать логику скрипта. Если скрипт становится слишком сложным для тестирования, это сигнал переписать его на Go (особенно если это часть основного приложения).
Пример кода
BASH#!/usr/bin/env batsload 'test_helper'@test "обработка флага --verbose" {run ./build.sh --verbose[ "$status" -eq 0 ][[ "$output" == *"Building..."* ]]}@test "скрипт падает при отсутствии GOOS" {unset GOOSrun ./build.sh[ "$status" -ne 0 ][[ "$output" == *"GOOS is required"* ]]}@test "мок docker-команды" {# подменяем docker на заглушкуexport PATH="$BATS_TEST_DIRNAME/mocks:$PATH"run ./deploy.sh[ "$status" -eq 0 ][[ "$output" == *"docker build"* ]]}
Как отвечать на собеседовании
Начни с конкретного примера: "Да, для скрипта миграций в Go-проекте использовал Bats". Затем опиши, что именно тестировал и почему. Упомяни, что не покрываешь всё подряд - только критичные пути. Если спросят про альтернативы, скажи, что для сложной логики предпочитаешь переписать на Go, а bash оставить для простых задач.
Что проверяет интервьюер
Интервьюер хочет понять:
- умеешь ли ты писать тесты не только для основного кода, но и для инфраструктурных скриптов;
- понимаешь ли границы применимости bash-тестов;
- знаешь ли инструменты экосистемы (Bats, shellcheck);
- умеешь ли мокать внешние зависимости.
Типичные ошибки
- Тестировать только happy path, игнорируя обработку ошибок.
- Пытаться тестировать bash-скрипты через Go-тесты (это возможно, но неудобно и медленно).
- Не использовать
set -euo pipefail- без этого тесты могут давать ложноположительные результаты. - Мокать слишком много - если скрипт полностью замокан, тест не проверяет реальное поведение.
- Забывать про teardown - временные файлы и переменные окружения должны очищаться.
> Похожие задачи по backend
Как правильно работать с map и структурой в Go, чтобы избежать паники
Что такое кэширование и слои кэширования в контейнерах
Работал ли с systemd
Как долго хранятся логи
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью