Program Tip

셸 스크립트에 대한 단위 테스트

programtip 2020. 11. 14. 11:02
반응형

셸 스크립트에 대한 단위 테스트


내가 수년 동안 작업해온 거의 모든 제품에는 일정 수준의 셸 스크립트 (또는 Windows의 배치 파일, PowerShell 등)가 포함되어 있습니다. 대부분의 코드를 Java 또는 C ++로 작성했지만 항상 쉘 스크립트로 더 잘 수행되는 통합 또는 설치 작업이있는 것처럼 보였습니다.

따라서 쉘 스크립트는 제공된 코드의 일부가되므로 컴파일 된 코드처럼 테스트해야합니다. 누구든지 shunit2 와 같은 쉘 스크립트 단위 테스트 프레임 워크에 대한 경험이 있습니까? 지금은 주로 Linux 쉘 스크립트에 관심이 있습니다. 테스트 하네스가 다른 xUnit 프레임 워크의 기능과 사용 편의성을 얼마나 잘 복제하는지, 그리고 CruiseControl 또는 Hudson과 같은 연속 빌드 시스템과의 통합이 얼마나 쉬운 지 알고 싶습니다.


업데이트 2019-03-01 : 내 선호는 지금 박쥐 입니다. 나는 작은 프로젝트에서 몇 년 동안 그것을 사용했습니다. 나는 깨끗하고 간결한 구문을 좋아합니다. CI / CD 프레임 워크와 통합하지는 않았지만 종료 상태는 제품군의 전체적인 성공 / 실패를 반영합니다. 이는 아래에 설명 된 shunit2보다 낫습니다.


이전 답변 :

Linux 환경에서 Java / Ruby 웹 애플리케이션과 관련된 쉘 스크립트에 shunit2사용 하고 있습니다. 사용하기 쉬웠으며 다른 xUnit 프레임 워크에서 크게 벗어나지 않았습니다.

CruiseControl 또는 Hudson / Jenkins와의 통합을 시도하지 않았지만 다른 수단을 통해 지속적 통합을 구현할 때 다음과 같은 문제가 발생했습니다.

  • 종료 상태 : 테스트 스위트가 실패하면 shunit2는 0이 아닌 종료 상태를 사용하여 실패를 전달하지 않습니다. 따라서 shunit2 출력을 구문 분석하여 제품군의 통과 / 실패를 결정하거나 shunit2를 일부 연속 통합 프레임 워크가 예상 한대로 작동하도록 변경하여 종료 상태를 통해 통과 / 실패를 전달해야합니다.
  • XML 로그 : shunit2는 결과의 JUnit 스타일 XML 로그를 생성하지 않습니다.

왜 아무도 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

@ blake-mizerany의 Roundup은 훌륭하게 들리며 앞으로도 활용해야하지만 여기에 단위 테스트를 만드는 "가난한"접근 방식이 있습니다.

  • 테스트 가능한 모든 것을 함수로 분리하십시오.
  • 외부 파일로 기능을 이동 말 functions.shsource는 스크립트로. source `dirname $0`/functions.sh이 목적으로 사용할 수 있습니다 .
  • functions.sh에서 아래 if 조건에 테스트 케이스를 삽입합니다.

    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 $?
    )

모집 : http://bmizerany.github.com/roundup/

자세히 설명하는 README의 기사에 대한 링크가 있습니다.


roundupshunit2 외에도 shell 단위 테스트 도구에 대한 개요에는 assert.shshelltestrunner가 포함 되었습니다 .

I mostly agree with roundup author's critique of shunit2 (some of it subjective), so I excluded shunit2 after looking at the documentation and examples. Although, it did look familiar having some experience with jUnit.

In my opinion shelltestrunner is the most original of the tools I've looked at since it uses simple declarative syntax for test case definition. As usual, any level of abstraction gives some convenience at the cost of some flexibility. Even though, the simplicity is attractive I found the tool too limiting for the case I had, mainly because of the lack of a way to define setup/tearDown actions (for example, manipulate input files before a test, remove state files after a test, etc.).

I was at first a little confused that assert.sh only allows asserting either output or exit status, while I needed both. Long enough to write a couple of test cases using roundup. But I soon found the roundup's set -e mode inconvenient as non-zero exit status is expected in some cases as a means of communicating the result in addition to stdout, which makes the test case fail in said mode. One of the samples shows the solution:

status=$(set +e ; rup roundup-5 >/dev/null ; echo $?)

But what if I need both the non-zero exit status and the output? I could, of course, set +e before invocation and set -e after or set +e for the whole test case. But that's against the roundup's principle "Everything is an Assertion". So it felt like I'm starting to work against the tool.

By then I've realized the assert.sh's "drawback" of allowing to only assert either exit status or output is actually a non-issue as I can just pass in test with a compound expression like this

output=$($tested_script_with_args)
status=$?
expected_output="the expectation"
assert_raises "test \"$output\" = \"$expected_output\" -a $status -eq 2"

As my needs were really basic (run a suite of tests, display that all went fine or what failed), I liked the simplicity of assert.sh, so that's what I chose.


After looking for a simple unit test framework for shell that could generate xml results for Jenkins and not really finding anything, I wrote one.

It's on sourceforge - the project's name is jshu.

http://sourceforge.net/projects/jshu


You should try out the assert.sh lib, very handy, easy to use

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

I recently released new testing framework called shellspec.

shellspec is BDD style testing framework. It's works on POSIX compatible shell script including bash, dash, ksh, busybox etc.

Of course, the exit status reflects the result of running of the specs and it's has TAP-compliant formatter.

The specfile is close to natural language and easy to read, and also it's shell script compatible syntax.

#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

참고URL : https://stackoverflow.com/questions/971945/unit-testing-for-shell-scripts

반응형