Модульное тестирование для сценариев оболочки



почти каждый продукт, над которым я работал на протяжении многих лет, включал некоторый уровень сценариев оболочки (или пакетных файлов, PowerShell и т. д. в Windows.) Несмотря на то, что мы написали большую часть кода на Java или C++, всегда казалось, что некоторые задачи интеграции или установки лучше выполняются с помощью сценария оболочки.



таким образом, скрипты оболочки становятся частью поставляемого кода и поэтому должны быть протестированы так же, как скомпилированный код. Есть ли у кого опыт работы с оболочки сценариев модульных тестов, которые существуют, например shunit2 ? Меня в основном интересуют скрипты оболочки Linux на данный момент; я хотел бы знать, насколько хорошо тестовый жгут дублирует функциональность и простоту использования других фреймворков xUnit и насколько легко интегрироваться с системами непрерывной сборки, такими как CruiseControl или Hudson.

549   7  

7 ответов:

Я использую shunit2 для сценариев оболочки, связанных с веб-приложением Java/Ruby в среде Linux. Он был прост в использовании и не сильно отличался от других фреймворков xUnit.

Я не пробовал интегрироваться с CruiseControl или Hudson / Jenkins, но при реализации непрерывной интеграции с помощью других средств я столкнулся с этими проблемами:

  • состояние выхода: при сбое комплекта тестов shunit2 не использует ненулевое состояние выхода для связи неудача. Таким образом, вам либо нужно проанализировать выход shunit2, чтобы определить проход/сбой набора, либо изменить shunit2, чтобы вести себя так, как ожидают некоторые платформы непрерывной интеграции, передавая pass/fail через состояние выхода.
  • XML logs: shunit2 не создает XML-журнал результатов в стиле JUnit.

интересно, почему никто не упомянул летучие мыши. Это до современных и нажми-совместимыми.

описания:

#!/usr/bin/env bats

@test "addition using bc" {
  result="$(echo 2+2 | bc)"
  [ "$result" -eq 4 ]
}

Run:

$ bats addition.bats
 ✓ addition using bc

1 tests, 0 failures

Roundup by @blake-mizerany звучит здорово, и я должен использовать его в будущем, но вот мой "бедный человек" подход для создания модульных тестов:

  • отделите все тестируемые функции.
  • переместить функции во внешний файл, скажем functions.sh и source это в сценарий. Вы можете использовать source `dirname `/functions.sh для этой цели.
  • в конце functions.sh, встроить тестовые случаи в ниже, если состояние:

    if [[ "${BASH_SOURCE[0]}" == "" ]]; then
    fi
    
  • ваши тесты-это литеральные вызовы функций, за которыми следуют простые проверки кодов выхода и значений переменных. Я хотел бы добавить простую функцию полезности, как показано ниже, чтобы сделать его легко писать:

    function assertEquals()
    {
        msg=; shift
        expected=; shift
        actual=; shift
        if [ "$expected" != "$actual" ]; then
            echo "$msg EXPECTED=$expected ACTUAL=$actual"
            exit 2
        fi
    }
    
  • наконец, запустить functions.sh непосредственно для выполнения тестов.

вот пример, чтобы показать подход:

    #!/bin/bash
    function adder()
    {
        return $((+))
    }

    (
        [[ "${BASH_SOURCE[0]}" == "" ]] || exit 0
        function assertEquals()
        {
            msg=; shift
            expected=; shift
            actual=; 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 $?
    )

Раундап: http://bmizerany.github.com/roundup/

есть ссылка на статью в README, объясняющую это подробно.

кроме Раундап и shunit2 мой обзор инструментов модульного тестирования оболочки также включены assert.sh и shelltestrunner.

Я в основном согласен с критикой автора roundup shunit2 (некоторые из них субъективны), поэтому я исключил shunit2 после просмотра документации и примеров. Хотя, это действительно выглядело знакомым, имея некоторый опыт работы с jUnit.

на мой взгляд shelltestrunner является наиболее оригинал инструментов, которые я рассматривал, поскольку он использует простой декларативный синтаксис для определения тестового случая. Как обычно, любой уровень абстракции дает некоторое удобство за счет некоторой гибкости. Несмотря на то, что простота привлекательна, я нашел инструмент слишком ограниченным для случая, который у меня был, главным образом из-за отсутствия способа определить действия установки/демонтажа (например, манипулировать входными файлами перед тестом, удалять файлы состояния после теста и т. д.).

Я сначала немного запутался что 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 так вот что я выбрал.

после поиска простой модульной тестовой платформы для оболочки, которая могла бы генерировать xml-результаты для Дженкинса и на самом деле ничего не найти, я написал один.

Это на sourceforge-имя проекта jshu.

http://sourceforge.net/projects/jshu

вы должны попробовать assert.sh lib, очень удобный, простой в использовании

local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent! 

Comments

    Ничего не найдено.