Модульное тестирование для сценариев оболочки - PullRequest
65 голосов
/ 09 июня 2009

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

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

Ответы [ 8 ]

48 голосов
/ 13 июня 2009

ОБНОВЛЕНИЕ 2019-03-01: сейчас я предпочитаю летучие мыши . Я использовал его в течение нескольких лет на небольших проектах. Мне нравится чистый, лаконичный синтаксис. Я не интегрировал его со средами CI / CD, но его состояние выхода отражает общий успех / неудачу пакета, который лучше, чем shunit2, как описано ниже.


ПРЕДЫДУЩИЙ ОТВЕТ:

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

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

  • Состояние выхода: при сбое набора тестов shunit2 не использует ненулевой статус выхода для сообщения о сбое. Таким образом, вы должны либо проанализировать выходные данные shunit2, чтобы определить, прошел или не прошел набор, либо изменить shunit2 на поведение, ожидаемое некоторыми средами непрерывной интеграции, сообщая прохождение / сбой через состояние выхода.
  • Журналы XML: shunit2 не создает XML-журнал результатов в стиле JUnit.
27 голосов
/ 09 января 2015

Интересно, почему никто не упомянул BATS . Он обновлен и соответствует TAP .

Опишите:

#!/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
20 голосов
/ 25 марта 2013

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

  • Разделите все проверяемое как функцию.
  • Переместите функции во внешний файл, скажем functions.sh и source в скрипт. Вы можете использовать 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 $?
    )
17 голосов
/ 26 декабря 2010

Roundup: http://bmizerany.github.com/roundup/

В README есть ссылка на статью с подробным объяснением.

8 голосов
/ 13 мая 2013

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

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

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

Сначала я был немного озадачен тем, что assert.sh позволяет утверждать только состояние вывода или выхода, в то время как мне нужны были оба. Достаточно долго, чтобы написать пару тестов с использованием сводки новостей. Но вскоре я обнаружил, что режим раунда set -e неудобен, так как в некоторых случаях ожидается ненулевое состояние выхода в качестве средства передачи результата в дополнение к стандартному выводу, что делает тестовый случай неудачным в указанном режиме. Один из образцов показывает решение:

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, и я выбрал именно это.

2 голосов
/ 09 мая 2018

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

local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent! 
2 голосов
/ 31 января 2014

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

Он находится на sourceforge - проект называется jshu.

http://sourceforge.net/projects/jshu

1 голос
/ 27 марта 2019

Я недавно выпустил новый фреймворк под названием 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...