Тестирование модулей для сценариев оболочки
Практически каждый продукт, над которым я работал на протяжении многих лет, включал некоторый уровень сценариев оболочки (или пакетных файлов, PowerShell и т.д. в Windows). Несмотря на то, что мы написали основную часть кода на Java или С++, всегда казалось, что есть некоторые задачи интеграции или установки, которые лучше выполнялись с помощью оболочки script.
Скрипты оболочки, таким образом, становятся частью отправленного кода и поэтому должны быть протестированы точно так же, как и скомпилированный код. Кто-нибудь имеет опыт работы с некоторыми оболочками script unit test, которые находятся там, например shunit2? На данный момент меня интересуют только сценарии оболочки Linux; Я хотел бы знать, насколько хорошо тестовая жгута дублирует функциональность и простоту использования других инфраструктур xUnit и насколько легко интегрироваться с системами непрерывной сборки, такими как CruiseControl или Hudson.
Ответы
Ответ 1
ОБНОВЛЕНИЕ 2019-03-01: сейчас я предпочитаю летучих мышей. Я использовал его в течение нескольких лет на небольших проектах. Мне нравится чистый, лаконичный синтаксис. Я не интегрировал его со средами CI/CD, но его состояние выхода отражает общий успех/неудачу пакета, который лучше, чем shunit2, как описано ниже.
ПРЕДЫДУЩИЙ ОТВЕТ:
Я использую shunit2 для сценариев оболочки, связанных с веб-приложением Java/Ruby в среде Linux. Он был прост в использовании и не сильно отличался от других платформ xUnit.
Я не пробовал интегрироваться с CruiseControl или Hudson/Jenkins, но при реализации непрерывной интеграции с помощью других средств я столкнулся с этими проблемами:
- Состояние выхода: при сбое набора тестов shunit2 не использует ненулевой статус выхода для сообщения о сбое. Таким образом, вы должны либо проанализировать выходные данные shunit2, чтобы определить, прошел или не прошел набор, либо изменить shunit2 на поведение, ожидаемое некоторыми средами непрерывной интеграции, сообщая прохождение/сбой через состояние выхода.
- Журналы XML: shunit2 не создает журнал результатов XML в стиле JUnit.
Ответ 2
Интересно, почему никто не упомянул летучих мышей. Это современное и TAP -compliant.
Опишите:
#!/usr/bin/env bats
@test "addition using bc" {
result="$(echo 2+2 | bc)"
[ "$result" -eq 4 ]
}
Бежать:
$ bats addition.bats
✓ addition using bc
1 tests, 0 failures
Ответ 3
Roundup by @blake-mizerany отлично звучит, и я должен использовать его в будущем, но вот мой подход "плохого человека" для создания модульных тестов:
- Отделить все, что можно проверить как функцию.
- Переместите функции во внешний файл, скажем
functions.sh
и source
в script. Вы можете использовать source `dirname $0`/functions.sh
для этой цели.
-
В конце functions.sh
вставьте свои тестовые примеры в состояние ниже:
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
fi
-
Ваши тесты являются буквальными вызовами функций, за которыми следуют простые проверки кодов выхода и значений переменных. Мне нравится добавлять простую функцию утилиты, как показано ниже, чтобы упростить ее запись:
function assertEquals()
{
msg=$1; shift
expected=$1; shift
actual=$1; shift
if [ "$expected" != "$actual" ]; then
echo "$msg EXPECTED=$expected ACTUAL=$actual"
exit 2
fi
}
-
Наконец, запустите functions.sh
непосредственно для выполнения тестов.
Вот пример, чтобы показать подход:
#!/bin/bash
function adder()
{
return $(($1+$2))
}
(
[[ "${BASH_SOURCE[0]}" == "${0}" ]] || exit 0
function assertEquals()
{
msg=$1; shift
expected=$1; shift
actual=$1; shift
/bin/echo -n "$msg: "
if [ "$expected" != "$actual" ]; then
echo "FAILED: EXPECTED=$expected ACTUAL=$actual"
else
echo PASSED
fi
}
adder 2 3
assertEquals "adding two numbers" 5 $?
)
Ответ 4
Roundup:
http://bmizerany.github.com/roundup/
В README есть ссылка на статью, подробно объясняющую ее.
Ответ 5
В дополнение к roundup и shunit2 мой обзор инструментов модульного тестирования оболочки также включал assert.sh и shelltestrunner.
Я в основном согласен с критической оценкой автора shunit2 (некоторые из них субъективны), поэтому я исключил shunit2 после просмотра документации и примеров. Хотя, это выглядело знакомо, имея некоторый опыт с jUnit.
На мой взгляд, shelltestrunner - самый оригинальный инструмент, на который я смотрел, поскольку он использует простой декларативный синтаксис для определения тестового примера. Как обычно, любой уровень абстракции дает некоторое удобство за счет некоторой гибкости. Несмотря на то, что простота привлекательна, я нашел инструмент слишком ограничивающим для моего случая, в основном из-за отсутствия способа определить действия setup/tearDown (например, манипулировать входными файлами перед тестом, удалять файлы состояния после теста, так далее.).
Сначала я был немного озадачен тем, что assert.sh позволяет утверждать только состояние вывода или выхода, в то время как мне нужны были оба. Достаточно долго, чтобы написать пару тестов с использованием сводки новостей. Но вскоре я обнаружил, что режим set -e
неудобен, так как в некоторых случаях ожидается ненулевое состояние выхода в качестве средства передачи результата в дополнение к stdout, что делает тестовый случай неудачным в указанном режиме. Один из примеров показывает решение:
status=$(set +e ; rup roundup-5 >/dev/null ; echo $?)
Но что, если мне нужен как ненулевой статус выхода, так и выход? Конечно, я мог бы set +e
до вызова и set -e
после или set +e
для всего тестового примера. Но это противоречит принципу сводки "Все является утверждением". Мне казалось, что я начинаю работать против инструмента.
К тому времени я понял, что "недостаток" assert.sh в том, что он позволяет утверждать только состояние выхода или выход, на самом деле не является проблемой, поскольку я могу просто пройти test
с составным выражением, подобным этому.
output=$($tested_script_with_args)
status=$?
expected_output="the expectation"
assert_raises "test \"$output\" = \"$expected_output\" -a $status -eq 2"
Поскольку мои потребности были действительно базовыми (запустить набор тестов, показать, что все прошло нормально или что не получилось), мне понравилась простота assert.sh, и то, что я выбрал.
Ответ 6
После поиска простой фреймворка unit test для оболочки, который мог бы генерировать xml-результаты для Jenkins и не нашел ничего, я написал один.
Это на sourceforge - имя проекта jshu.
http://sourceforge.net/projects/jshu
Ответ 7
Вы должны попробовать assert.sh lib, очень удобный, простой в использовании
local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!
Ответ 8
Недавно я выпустил новый фреймворк для тестирования под названием shellspec.
shellspec - это среда тестирования в стиле BDD. Он работает на POSIX-совместимом сценарии оболочки, включая bash, dash, ksh, busybox и т.д.
Конечно, состояние выхода отражает результат выполнения спецификаций и имеет TAP-совместимый форматер.
Specfile близок к естественному языку и прост для чтения, а также поддерживает синтаксис, совместимый со сценарием оболочки.
#shellcheck shell=sh
Describe 'sample'
Describe 'calc()'
calc() { echo "$(($*))"; }
It 'calculates the formula'
When call calc 1 + 2
The output should equal 3
End
End
End