단위 테스트 bash 스크립트


112

Java 코드 외에 실행되는 일부 bash 스크립트가있는 시스템이 있습니다. 우리는 깨질 수있는 모든 것을 테스트하려고하고 있고 그 bash 스크립트가 깨질 수 있기 때문에 우리는 그것들을 테스트하고 싶습니다.

문제는 bash 스크립트를 테스트하기가 어렵다는 것입니다.

bash 스크립트를 테스트하는 방법이나 모범 사례가 있습니까? 아니면 bash 스크립트 사용을 중단하고 테스트 가능한 대체 솔루션을 찾아야합니까?




기존 도구의 개요 : medium.com/wemake-services/...
sobolevn

답변:


48

실제로 Bourne 기반 셸 스크립트를위한 xUnit 기반 단위 테스트 프레임 워크 인 shunit2 가 있습니다 . 나는 그것을 직접 사용하지 않았지만 확인해 볼 가치가있을 것입니다.

유사한 질문이 이전에 제기되었습니다.


3
나는 shunit2 (버전 2.1.6)가 현재까지 조금 깨 졌다고 주장 할 수 있습니다. assertNull 및 assertNotNull은 직접 값을 제공하더라도 작동하지 않습니다. assertEquals는 잘 작동하지만 지금은 내 자신을 굴려야 할 것 같습니다.
labyrinth

@labyrinth, 문제가 다음과 같은 경우가 아니라고 확신 하십니까? github.com/kward/shunit2/issues/53 "assertNull을 올바르게 사용하는 방법?"
Victor Sergienko 2017

1
@Victor 내가 큰 따옴표를 충분히 조심하지 않았을 가능성이 있습니다. 곧 shunit2 또는 일부 bash 단위 테스트 시스템이 매우 유용한 역할로 돌아갈 것입니다. 나는 그것을 다시 시도 할 것이다.
미로

5
나는 사용자와 shunit2에 때때로 기여 오전, 나는이 프로젝트는 건재 2019 년에 있음을 확인할 수 있습니다
하비 알렉스

31

토론 그룹에서 다음 답변을 받았습니다.

외부 파일에서 프로 시저 (함수, 이름이 무엇이든)를 가져 오는 것이 가능합니다. 이것이 테스트 스크립트 작성의 핵심입니다. 스크립트를 독립적 인 절차로 분할 한 다음 실행중인 스크립트와 테스트 스크립트로 가져올 수있는 다음 실행 스크립트를 가능한 한 간단하게 만듭니다.

이 방법은 스크립트에 대한 종속성 주입과 같으며 합리적으로 들립니다. bash 스크립트를 피하고 더 테스트 가능하고 덜 모호한 언어를 사용하는 것이 좋습니다.


4
찬성 또는 반대 투표를해야하는지 잘 모르겠습니다. 한편으로는 작은 부분으로 나누는 것이 좋지만, 다른 한편으로는 커스텀 스크립트 세트가 아닌 프레임 워크가 필요합니다
mpapis 2011 년

10
bash에는 문제가 없지만 (많은 스크립트를 작성했습니다) 마스터하기 어려운 언어입니다. 내 경험 법칙은 스크립트가 테스트가 필요할만큼 충분히 크면 쉽게 테스트 할 수있는 스크립팅 언어로 이동해야한다는 것입니다.
Doug

1
그러나 때로는 사용자의 셸에서 얻을 수있는 무언가가 필요합니다. 쉘 스크립트를 사용하지 않고 어떻게 할 수 있는지는 분명하지 않습니다.
Itkovian

@Itkovian-예를 들어 npm을 사용하여 실행 파일을 경로로 내보낼 수 있으므로 소싱이 필요하지 않습니다 (npm 패키지를 전역 적으로 설치해야 함)
Eliran Malka

1
bash를 사용하지 않는 것에 대한 조언을 따를 것입니다. :)
Maciej Wawrzyńczuk

30

TAP 호환 Bash 테스트 : Bash 자동 테스트 시스템

Test Anything Protocol 인 TAP는 테스트 장치의 테스트 모듈 간의 간단한 텍스트 기반 인터페이스입니다. TAP는 Perl 용 테스트 도구의 일부로 시작되었지만 이제는 C, C ++, Python, PHP, Perl, Java, JavaScript 등으로 구현되었습니다.


14
그것은 무엇 TAP 가치가 공개가 그리고 왜, 그렇지 않으면 그냥 의미없는 하나의 관리입니다해야 복사 - 붙여 넣기
OM-NOM-NOM

@ om-nom-nom : 지금 TAP 사이트에 연결했습니다.
Janus Troelsen 2014 년

7
아무도 말할 수없는 말을하지 않았기 때문에 : TAP = Test Anything Protocol
JW.

9

Nikita Sobolev는 몇 가지 다른 bash 테스트 프레임 워크를 비교하는 훌륭한 블로그 게시물을 작성했습니다. Bash 애플리케이션 테스트

참을성이없는 분들께 : Nikita의 결론은 Bats 를 사용하는 것이었지만 Nikita는 2013 년부터 원래 Bats 프로젝트가 적극적으로 유지되지 않았기 때문에 앞으로 나에게 사용할 것으로 보이는 Bats-core 프로젝트를 놓친 것으로 보입니다.


7

Epoxy 는 주로 다른 소프트웨어를 테스트하기 위해 디자인 한 Bash 테스트 프레임 워크이지만, 자체Carton을 포함하여 bash 모듈도 테스트하는 데 사용합니다 .

주요 이점은 상대적으로 낮은 코딩 오버 헤드, 무제한 주장 중첩 및 검증 할 주장의 유연한 선택입니다.

Red Hat의 일부에서 사용하는 프레임 워크 인 BeakerLib와 비교 하여 프레젠테이션을 만들었습니다 .


6

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
 }

4
첫째, bash 스크립트는 읽기 어렵습니다. 둘째, 잠금 파일이 생성 된 bash 스크립트의 PID로 잠금 파일이 생성되었는지 확인하는 것과 같이 기대가 복잡합니다.
nimcap 2009-08-27

10
더 중요한 것은 셸 스크립트는 일반적으로 많은 부작용이 있고 파일 시스템, 네트워크 등과 같은 시스템 리소스를 활용하기 때문에 테스트하기 어렵다는 것입니다. 이상적으로는 단위 테스트는 부작용이없고 시스템 리소스에 의존하지 않습니다.
jayhendren 2014

4

사용하기 쉽고 유용한 도구를 원했기 때문에 shellspec을 만들었습니다 .

순수한 POSIX 쉘 스크립트로 작성되었습니다. shunit2보다 많은 쉘로 테스트했습니다. 그것은 박쥐 / 박쥐 코어보다 강력한 기능을 가지고 있습니다.

예를 들어, 중첩 된 블록 지원, 모의 / 스텁 용이, 건너 뛰기 / 보류 용이, 매개 변수화 된 테스트, 어설 션 라인 번호, 라인 번호 별 실행, 병렬 실행, 임의 실행, TAP / JUnit 포맷터, 커버리지 및 CI 통합, 프로파일 러 등 .

프로젝트 페이지에서 데모를 참조하십시오.


3

나는 Bash 스크립트 테스트에서 JUnit과 같은 출력을 생성하는 유틸리티 인 shell2junit을 아주 좋아 합니다. 생성 된 보고서는 Jenkins 및 Bamboo 용 JUnit 플러그인과 같은 연속 통합 시스템에서 읽을 수 있기 때문에 유용합니다.

shell2junit 같은 포괄적 인 배쉬 스크립트 프레임 워크를 제공하지 않지만 shunit2을 , 당신이 테스트 결과의 좋은보고를 할 수 없습니다.


3

bashtest 시도 하십시오 . 스크립트를 테스트하는 간단한 방법입니다. 예를 들어, 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

여기여기에서 몇 가지 예 를 찾을 수 있습니다.


3

아마도 이것은 사용되거나 기여할 수 있습니다.

https://thorsteinssonh.github.io/bash_test_tools/

내가 생각하기에 CI에 좋고 쉘 환경을 원하는 사람들에게 좋은 TAP 프로토콜로 결과를 작성하려고했습니다. 나는 어떤 것들은 쉘 환경에서 실행될 것이라고 생각한다. 그래서 어떤 이들은 쉘 환경에서 테스트되어야한다고 주장 할 것이다.


3

assert.sh를 시도 하십시오.

source "./assert.sh"

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

도움이 되었기를 바랍니다.


3

나는 아무도 OSHT에 대해 이야기하지 않았다는 것을 믿을 수 없습니다 ! 둘 다 와 호환됩니다 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

마지막 테스트는 "not ok"로 표시되지만 종료 코드는 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

JUnit 출력을 생성하도록 설정 OSHT_JUNIT하거나 전달 -j합니다. JUnit은 prove(1).

내가 가진 주장을 자신의 파일을 소싱하고 실행하여이 라이브러리를 모두 테스트 기능을 사용하고 IS/ OK사용하여 자신의 부정 및 스크립트 RUN/을 NRUN. 저에게이 프레임 워크는 최소한의 오버 헤드로 가장 많은 이득을 제공합니다.


1

여기에 제시된 많은 솔루션을 시도했지만 대부분의 솔루션이 부피가 크고 사용하기 어려웠 기 때문에 자체 테스트 프레임 워크를 구축했습니다 : https://github.com/meonlol/t-bash

JUnit 스타일 어설 션의 기본 세트를 사용하여 간단하게 직접 실행할 수있는 저장소에있는 하나의 파일입니다.

여러 내부 프로젝트에서 전문적으로 사용했으며 bash 스크립트를 매우 안정적이고 회귀에 강하게 만들 수있었습니다.



0

Outthentic을 살펴보면 간단하고 다양한 언어 (Perl, Python, Ruby, Bash on choice) 및 크로스 플랫폼 (Linux, Windows) 프레임 워크로 확장하여 모든 명령 줄 애플리케이션을 테스트 할 수 있습니다.


-2

파이썬 에 엄청난 이점이 있을 때 더 큰 스크립트에 bash를 사용하는 것을 정당화하기가 어렵다는 것을 알았습니다 .

  • Try / Except를 사용하면 오류 발생시 변경 사항을 취소 할 수있는 더 강력한 스크립트를 작성할 수 있습니다.
  • if [ x"$foo" = x"$bar"]; then ...오류가 발생하기 쉬운 ' ' 와 같은 모호한 구문을 사용할 필요가 없습니다 .
  • 다음을 사용하여 옵션 및 인수를 쉽게 구문 분석 getopt모듈을 합니다 (그리고 인수를 파싱하기위한 더 쉬운 모듈이 있지만 이름은 나를 탈출합니다).
  • Python을 사용하면 기본 문자열 및 배열 대신 목록 / 사전 및 객체로 작업 할 수 있습니다.
  • 정규식, 데이터베이스와 같은 적절한 언어 도구에 액세스합니다 (모든 것을 mysqlbash 에서 명령 으로 파이프 할 수 있지만 코드를 작성하는 가장 좋은 방법은 아닙니다).
  • $*또는 "$*"또는 "$@"또는 $1또는 의 올바른 형식을 사용하는 것에 대해 걱정할 필요가 없습니다 "$1". 파일 이름의 공백은 문제 등이 아닙니다.

이제는 가장 간단한 스크립트에만 bash를 사용합니다.


3
파이썬이 장점을 가지고 있다는 사실을 부정하지는 않지만 두 번째 요점은 그다지 적절하지 않습니다. 같은 비교가 if [[ $foo = $bar ]]; then .... 이것은 파이썬이 제공하는 것보다 낫지는 않지만 당신이 제시 한 것보다 낫습니다.
Shrikant Sharat 2011 년

8
일부 시스템 (예를 들어 내장)은 파이썬을 사용할 수 없으며 추가 항목을 설치할 수 없거나 설치하고 싶지 않습니다.
Rui Marques

2
나는 개인적으로 bash를 좋아하지만 약간의 증언이 될 수 있다는 데 동의합니다. 일반적으로 훨씬 더 적극적으로 대처해야하는 반면 Python에서는 오류가 발생한 후에 해결할 수 있습니다 . 그러나 bash에는 trap정규식 (예 :)뿐만 아니라 (오류 발생시 정리 / 실행 취소 [[ $1 =~ ^[1-3]{3}$ ]]) 기능이 있습니다. 나는 당신이 사용한 모호한 구문이 testbash가 아닌의 이전 구현에 대한 참조라고 확신합니다 . 강타는 자주 하나의 파이프로 ... 기존 명령 줄 도구와의 인터페이스를 위해 중대하다 awk또는 grep파이썬 대안보다 훨씬 쉽습니다.
여섯

1
BTW, 당신이 언급했던 파서 모듈은 아마도 optparse그 후속 모듈 일 것 argparse입니다. 나는 아무도 getopt모듈을 사용하는 것을 본 적이 없으며 개인적으로 사용하지 않았습니다. 그러나 getopt유틸리티는 훌륭합니다. 셸에서 인수 구문 분석을 수행하는 것은 좋은 패턴을 얻은 후에는 전혀 문제가되지 않습니다. git 스타일의 하위 명령 등을 구현하지 않는 한 큰 문제가 아닙니다.
여섯

Python은 bash가 도달 할 수있는 모든 곳에서 실행되지 않습니다. bash와 python, 동일한 코드 로직을 테스트하고 둘 다 뭔가를 요청했기 때문에 그렇게 말합니다. Bash는 액세스 할 수있는 모든 디렉토리에 들어갔습니다. 반면에 파이썬은 일부 디렉토리 권한 및 파일과 매우 빠르게 증가 및 감소하는 디렉토리를 처리 할 수 ​​없었습니다.
vianna77
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.