Модульное тестирование bash-скриптов
-
20-09-2019 - |
Вопрос
У нас есть система, в которой помимо кода Java работают несколько сценариев Bash.Поскольку мы пытаемся протестировать все, что может сломаться, а эти сценарии bash могут сломаться, мы хотим их протестировать.
Проблема в том, что bash-скрипты сложно тестировать.
Есть ли способ или лучшая практика для тестирования сценариев Bash?Или нам следует отказаться от использования bash-скриптов и поискать альтернативные решения, которые можно протестировать?
Решение 2
Я получил следующий ответ от дискуссионной группы:
можно импортировать (включить, что угодно) процедуру (функцию, как бы она ни называлась) из внешнего файла.Это ключ к написанию сценарий тестирования :вы разбиваете свой скрипт на независимые процедуры , которые затем могут быть импортированы как в ваш работающий скрипт, так и в ваш тестируемый скрипт, после чего ваш работающий скрипт должен быть максимально простым.
Этот метод похож на внедрение зависимостей для сценариев и звучит разумно.Предпочтительнее избегать bash-скриптов и использовать более тестируемый и менее непонятный язык.
Другие советы
На самом деле существует шунит2, платформа модульного тестирования на основе xUnit для сценариев оболочки на основе Bourne.Сам я им не пользовался, но, возможно, стоит проверить.
Подобные вопросы уже задавались:
КРАН-совместимое тестирование Bash: Система автоматизированного тестирования Bash
TAP, Test Anything Protocol, представляет собой простой текстовый интерфейс между модулями тестирования в тестовом комплекте.TAP начал свою жизнь как часть тестового пакета Perl, но теперь имеет реализации на C, C++, Python, PHP, Perl, Java, JavaScript и других.
Эпоксидная смола — это среда тестирования Bash, которую я разработал в основном для тестирования другого программного обеспечения, но я также использую ее для тестирования модулей Bash, в том числе сам и Картонная коробка.
Основными преимуществами являются относительно низкие затраты на кодирование, неограниченное вложение утверждений и гибкий выбор утверждений для проверки.
я сделал презентация сравнивая это с Библиотека стаканов — фреймворк, используемый некоторыми в Red Hat.
Никита Соболев написал отличный пост в блоге, сравнивая несколько различных фреймворков для тестирования bash: Тестирование Bash-приложений
Для нетерпеливых:Вывод Никиты заключался в том, чтобы использовать Летучие мыши но, похоже, Никита промахнулся Летучие мыши-ядро проект, который, как мне кажется, будет использоваться в дальнейшем, поскольку оригинальный проект Bats активно не поддерживается с 2013 года.
Почему вы говорите, что тестировать bash-скрипты «трудно»?
Что не так с тестовыми обертками, например:
#!/bin/bash
set -e
errors=0
results=$($script_under_test $args<<ENDTSTDATA
# inputs
# go
# here
#
ENDTSTDATA
)
[ "$?" -ne 0 ] || {
echo "Test returned error code $?" 2>&1
let errors+=1
}
echo "$results" | grep -q $expected1 || {
echo "Test Failed. Expected $expected1"
let errors+=1
}
# and so on, et cetera, ad infinitum, ad nauseum
[ "$errors" -gt 0 ] && {
echo "There were $errors errors found"
exit 1
}
мне очень нравится оболочка2junit, утилита для генерации выходных данных в стиле JUnit из тестов сценариев Bash.Это полезно, поскольку созданный отчет затем может быть прочитан системами непрерывной интеграции, такими как подключаемые модули JUnit для Jenkins и Bamboo.
Хотя Shell2junit не предоставляет комплексную среду сценариев Bash, такую как шунит2, это позволяет вам получить хороший отчет о результатах испытаний.
Пытаться баштест.Это простой способ протестировать ваши скрипты.Например, у вас есть do-some-work.sh
которые меняют некоторые файлы конфигурации.Например, добавьте новую строку PASSWORD = 'XXXXX'
в файл конфигурации /etc/my.cfg
.
Вы пишете команды bash построчно, а затем проверяете вывод.
Установить:
pip3 install bashtest
Создание тестов — это просто написание команд bash.
Файл test-do-some-work.bashtest
:
# run the script
$ ./do-some-work.sh > /dev/null
# testing that the line "PASSWORD = 'XXXXX'" is in the file /etc/my.cfg
$ grep -Fxq "PASSWORD = 'XXXXX'" /etc/my.cfg && echo "YES"
YES
Запустите тесты:
bashtest *.bashtest
Ты можешь найти несколько примеров здесь и здесь
Возможно, это можно использовать или внести свой вклад в
https://thorsteinssonh.github.io/bash_test_tools/
Предназначен для записи результатов в протоколе TAP, который, как мне кажется, хорош для CI и для тех, кому нужны среды оболочки.Я предполагаю, что некоторые вещи выполняются в средах оболочки, поэтому некоторые могут утверждать, что их следует тестировать в их среде оболочки.
Попробуйте утверждать.sh
source "./assert.sh"
local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!
Надеюсь, поможет!
Я не могу поверить, что никто не говорил об этом ОШТ!Он совместим с оба TAP и JUnit, это чистая оболочка (то есть без участия других языков), она работает и автономно, она проста и понятна.
Тестирование выглядит так (фрагменты взяты со страницы проекта):
#!/bin/bash
. osht.sh
# Optionally, indicate number of tests to safeguard against abnormal exits
PLAN 13
# Comparing stuff
IS $(whoami) != root
var="foobar"
IS "$var" =~ foo
ISNT "$var" == foo
# test(1)-based tests
OK -f /etc/passwd
NOK -w /etc/passwd
# Running stuff
# Check exit code
RUNS true
NRUNS false
# Check stdio/stdout/stderr
RUNS echo -e 'foo\nbar\nbaz'
GREP bar
OGREP bar
NEGREP . # verify empty
# diff output
DIFF <<EOF
foo
bar
baz
EOF
# TODO and SKIP
TODO RUNS false
SKIP test $(uname -s) == Darwin
Простой запуск:
$ bash test.sh
1..13
ok 1 - IS $(whoami) != root
ok 2 - IS "$var" =~ foo
ok 3 - ISNT "$var" == foo
ok 4 - OK -f /etc/passwd
ok 5 - NOK -w /etc/passwd
ok 6 - RUNS true
ok 7 - NRUNS false
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
ok 9 - GREP bar
ok 10 - OGREP bar
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
not ok 13 - TODO RUNS false # TODO Test Know to fail
Последний тест показывает «не в порядке», но код выхода равен 0, потому что это ошибка. TODO
.Также можно установить подробный:
$ OSHT_VERBOSE=1 bash test.sh # Or -v
1..13
# dcsobral \!= root
ok 1 - IS $(whoami) != root
# foobar =\~ foo
ok 2 - IS "$var" =~ foo
# \! foobar == foo
ok 3 - ISNT "$var" == foo
# test -f /etc/passwd
ok 4 - OK -f /etc/passwd
# test \! -w /etc/passwd
ok 5 - NOK -w /etc/passwd
# RUNNING: true
# STATUS: 0
# STDIO <<EOM
# EOM
ok 6 - RUNS true
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
ok 7 - NRUNS false
# RUNNING: echo -e foo\\nbar\\nbaz
# STATUS: 0
# STDIO <<EOM
# foo
# bar
# baz
# EOM
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
# grep -q bar
ok 9 - GREP bar
# grep -q bar
ok 10 - OGREP bar
# \! grep -q .
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
not ok 13 - TODO RUNS false # TODO Test Know to fail
Переименуйте его, чтобы использовать .t
расширение и поместите его в t
подкаталог, и вы можете использовать prove(1)
(часть Perl), чтобы запустить его:
$ prove
t/test.t .. ok
All tests successful.
Files=1, Tests=13, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.11 cusr 0.16 csys = 0.31 CPU)
Result: PASS
Набор OSHT_JUNIT
или пройти -j
для получения вывода JUnit.JUnit также можно комбинировать с prove(1)
.
Я использовал эту библиотеку как для функций тестирования, получая файлы, а затем запуская утверждения с помощью IS
/OK
и их негативы, а также сценарии с использованием RUN
/NRUN
.На мой взгляд, эта структура обеспечивает максимальную выгоду при минимальных накладных расходах.
я создал спецификация оболочки потому что мне нужен был простой в использовании и полезный инструмент.
Он написан чистым скриптом оболочки POSIX.Он протестирован со многими оболочками, кроме Shunit2.Он обладает более мощными функциями, чем bats/bats-core.
Например, поддержка вложенных блоков, легкость имитации/заглушки, легкость пропуска/ожидания, параметризованные тесты, номер строки утверждения, выполнение по номеру строки, параллельное выполнение, случайное выполнение, форматировщик TAP/JUnit, интеграция покрытия и CI, профилировщик и т. д. .
Смотрите демо на странице проекта.
Я испробовал множество представленных здесь решений, но большинство из них показались мне громоздкими и сложными в использовании, поэтому я создал свою собственную небольшую среду тестирования: https://github.com/meonlol/t-bash
Это всего лишь один файл в репозитории, который вы можете просто запустить напрямую с базовым набором утверждений стиля JUnit.
Я профессионально использовал его в нескольких внутренних проектах и смог сделать наши bash-скрипты суперстабильными и устойчивыми к регрессии.
Возможно, вы захотите взглянуть на bash_unit:
Взгляни на аутентичный, Это простой, расширяемый многими языками (Perl, Python, Ruby, Bash по выбору) и кроссплатформенный (Linux, Windows) фреймворк для тестирования любых приложений командной строки.
Мне было трудно оправдать использование bash для более крупных сценариев, когда Питон имеет такие огромные преимущества:
- Try/Except позволяет писать более надежные сценарии с возможностью отмены изменений в случае ошибки.
- Вам не обязательно использовать непонятный синтаксис, например '
if [ x"$foo" = x"$bar"]; then ...
', который подвержен ошибкам. - Простой анализ опций и аргументов с помощью
getopt
модуль (есть еще более простой модуль для анализа аргументов, но его название ускользает от меня). - Python позволяет вам работать со списками/словами и объектами вместо базовых строк и массивов.
- Доступ к соответствующим языковым инструментам, таким как регулярные выражения и базы данных (конечно, вы можете передать все в
mysql
команду в bash, но это не самый приятный способ написания кода). - Не нужно беспокоиться об использовании правильной формы
$*
или"$*"
или"$@"
или$1
или"$1"
, пробелы в именах файлов не являются проблемой и т. д., т. д. и т. п.
Сейчас я использую bash только для самых простых скриптов.