Các tập lệnh bash của Unit Testing


112

Chúng tôi có một hệ thống có một số tập lệnh bash chạy bên cạnh mã Java. Vì chúng tôi đang cố gắng kiểm tra mọi thứ có thể bị vỡ và các tập lệnh bash đó có thể bị hỏng, chúng tôi muốn kiểm tra chúng.

Vấn đề là rất khó để kiểm tra các tập lệnh bash.

Có cách nào hoặc phương pháp hay nhất để kiểm tra tập lệnh bash không? Hay chúng ta nên bỏ sử dụng tập lệnh bash và tìm kiếm các giải pháp thay thế có thể kiểm tra được?




Tổng quan về các công cụ hiện có: medium.com/wemake-services/…
sobolevn

Câu trả lời:


48

Thực sự có một shunit2 , một khung kiểm tra đơn vị dựa trên xUnit cho các tập lệnh shell dựa trên Bourne. Tôi chưa sử dụng nó bản thân mình, nhưng nó có thể đáng để thử.

Các câu hỏi tương tự đã được hỏi trước đây:


3
Tôi có thể khẳng định (dự định chơi chữ) rằng shunit2 (phiên bản 2.1.6) đã bị hỏng một chút cho đến nay. Khẳng địnhNull và khẳng địnhNotNull không hoạt động, ngay cả khi bạn cung cấp các giá trị trực tiếp cho chúng. khẳng địnhEquals hoạt động tốt, nhưng tôi nghĩ bây giờ tôi sẽ phải tự mình cố gắng.
mê cung vào

@labyrinth, bạn có chắc sự cố không phải là trường hợp này không: github.com/broken/shunit2/issues/53 "Làm thế nào để sử dụng khẳng định chính xác?"?
Victor Sergienko

1
@Victor Chắc chắn có thể tôi đã không đủ cẩn thận với dấu ngoặc kép của mình. Tôi sẽ sớm quay trở lại một vai trò mà ở đó shunit2 hoặc một số hệ thống kiểm tra đơn vị bash sẽ rất hữu ích. Tôi sẽ thử lại.
mê cung

5
Tôi là một người dùng và đôi khi đóng góp tới shunit2, và tôi có thể khẳng định rằng dự án vẫn còn sống và cũng trong năm 2019.
Alex Harvey

31

Tôi nhận được câu trả lời sau từ một nhóm thảo luận:

có thể nhập (bao gồm, bất cứ điều gì) một thủ tục (chức năng, bất cứ điều gì được đặt tên) từ một tệp bên ngoài. Đó là chìa khóa để viết tập lệnh thử nghiệm: bạn chia tập lệnh của mình thành các thủ tục độc lập, sau đó có thể được nhập vào cả tập lệnh đang chạy và tập lệnh thử nghiệm của bạn, sau đó bạn có tập lệnh đang chạy của mình càng đơn giản càng tốt.

Phương pháp này giống như phương pháp tiêm phụ thuộc cho các tập lệnh, và nghe có vẻ hợp lý. Nên tránh các tập lệnh bash và sử dụng ngôn ngữ dễ kiểm tra hơn và ít tối nghĩa hơn.


4
Tôi không chắc chắn nếu tôi nên bỏ phiếu lên hoặc xuống, một mặt chia đến các bộ phận nhỏ hơn là tốt, nhưng trên tay thứ hai tôi cần một khuôn khổ không phải là một tập hợp các kịch bản tùy chỉnh
mpapis

10
Mặc dù không có gì sai với bash (tôi đã viết rất nhiều script), nhưng nó là một ngôn ngữ khó để thành thạo. Nguyên tắc chung của tôi là nếu một tập lệnh đủ lớn để cần kiểm tra, có lẽ bạn nên chuyển sang ngôn ngữ kịch bản dễ kiểm tra.
Doug

1
Nhưng đôi khi bạn cần phải có thứ gì đó có thể được lấy nguồn từ vỏ của người dùng. Nó không rõ ràng đối với tôi như thế nào bạn muốn làm điều đó mà không cần đến một kịch bản shell
Itkovian

@Itkovian - bạn có thể, ví dụ, sử dụng NPM để xuất khẩu một thực thi để con đường, vì vậy không tìm nguồn cung ứng là cần thiết (gói NPM của bạn sẽ phải được cài đặt trên toàn cầu)
Eliran Malka

1
Tôi sẽ làm theo lời khuyên về việc không sử dụng bash. :)
Maciej Wawrzyńczuk

30

Kiểm tra Bash tuân thủ TAP : Hệ thống kiểm tra tự động Bash

TAP, Giao thức Thử nghiệm Bất cứ Điều gì, là một giao diện dựa trên văn bản đơn giản giữa các mô-đun thử nghiệm trong một khai thác thử nghiệm. TAP bắt đầu hoạt động như một phần của quá trình khai thác thử nghiệm cho Perl nhưng hiện đã triển khai bằng C, C ++, Python, PHP, Perl, Java, JavaScript và những thứ khác.


14
Nó có giá trị làm lộ những gì TAP là lý do tại sao và nên một dịch vụ chăm sóc, nếu không nó chỉ là vô nghĩa sao chép dán
om-nôm-nom

@ om-nom-nom: Tôi đã liên kết nó với trang TAP ngay bây giờ.
Janus Troelsen

7
Vì không ai khác nói điều không thể tin được: TAP = Test Anything Protocol
JW.

9

Nikita Sobolev đã viết một bài đăng trên blog tuyệt vời so sánh một số khung thử nghiệm bash khác nhau: Thử nghiệm các ứng dụng Bash

Đối với những người thiếu kiên nhẫn: Kết luận của Nikita là sử dụng Dơi nhưng có vẻ như Nikita đã bỏ lỡ dự án chính của Dơi mà dường như tôi là dự án sẽ sử dụng trong tương lai vì dự án Dơi ban đầu đã không được duy trì tích cực kể từ năm 2013.


7

Epoxy là một khung kiểm tra Bash mà tôi thiết kế chủ yếu để kiểm tra các phần mềm khác, nhưng tôi cũng sử dụng nó để kiểm tra các mô-đun bash, bao gồm cả chính nóCarton .

Ưu điểm chính là chi phí mã hóa tương đối thấp, lồng xác nhận không giới hạn và lựa chọn linh hoạt các xác nhận để xác minh.

Tôi đã thực hiện một bài thuyết trình so sánh nó với BeakerLib - một khuôn khổ được một số người ở Red Hat sử dụng.


6

Tại sao bạn lại nói rằng việc kiểm tra các tập lệnh bash là "khó"?

Có gì sai với các trình bao bọc thử nghiệm như:

 #!/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
Đầu tiên, các tập lệnh bash không dễ đọc. Thứ hai, các kỳ vọng phức tạp như kiểm tra xem tệp khóa có được tạo bằng PID của tập lệnh bash đã tạo ra nó hay không.
nimcap

10
Quan trọng hơn, thật khó để kiểm tra các tập lệnh shell vì chúng thường có một số lượng lớn các tác dụng phụ và sử dụng các tài nguyên hệ thống như hệ thống tệp, mạng, v.v. Lý tưởng nhất là các bài kiểm tra đơn vị không có tác dụng phụ và không phụ thuộc vào tài nguyên hệ thống.
jayhendren

4

Tôi đã tạo shellspec vì tôi muốn có một công cụ dễ sử dụng và hữu ích.

Nó được viết bởi tập lệnh shell POSIX thuần túy. Nó đã thử nghiệm với nhiều shell hơn shunit2. Nó có các tính năng mạnh mẽ hơn dơi / dơi-core.

Ví dụ: hỗ trợ khối lồng nhau, dễ mô phỏng / sơ khai, dễ dàng bỏ qua / đang chờ xử lý, kiểm tra tham số, số dòng xác nhận, thực thi theo số dòng, thực thi song song, thực thi ngẫu nhiên, định dạng TAP / JUnit, phạm vi bảo hiểm và tích hợp CI, trình biên dịch, v.v. .

Xem bản trình diễn trên trang dự án.


3

Tôi khá thích shell2junit , một tiện ích để tạo đầu ra giống JUnit từ các bài kiểm tra tập lệnh Bash. Điều này rất hữu ích vì báo cáo được tạo sau đó có thể được đọc bởi các hệ thống tích hợp liên tục, chẳng hạn như các trình cắm thêm JUnit cho Jenkins và Bamboo.

Mặc dù shell2junit không cung cấp khung kịch bản Bash toàn diện như shunit2 , nhưng nó cho phép bạn có báo cáo tốt về kết quả thử nghiệm.


3

Hãy thử bashtest . Đó là cách đơn giản để kiểm tra các tập lệnh của bạn. Ví dụ, bạn có do-some-work.shthay đổi một số tệp cấu hình. Ví dụ: thêm dòng mới PASSWORD = 'XXXXX'vào tệp cấu hình/etc/my.cfg .

Bạn viết lệnh bash từng dòng một và sau đó kiểm tra đầu ra.

Tải về:

pip3 install bashtest

Tạo các bài kiểm tra chỉ là viết các lệnh bash.

Tệp tin 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

Chạy thử nghiệm:

bashtest *.bashtest

Bạn có thể tìm thấy một số ví dụ ở đâyở đây


3

Có thể điều này có thể được sử dụng hoặc đóng góp vào

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

Dự định viết kết quả trong giao thức TAP mà tôi tưởng tượng là tốt cho CI và tốt cho những người muốn môi trường shell. Tôi tưởng tượng một số thứ chạy trong môi trường shell vì vậy, một số người có thể tranh luận nên được kiểm tra trong môi trường shell của chúng.


3

Hãy thử để khẳng định.sh

source "./assert.sh"

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

Hy vọng nó giúp!


3

Tôi không thể tin rằng không có ai nói về OSHT ! Nó tương thích với cả TAP và JUnit, nó là shell thuần túy (nghĩa là không có ngôn ngữ nào khác tham gia), nó cũng hoạt động độc lập, đơn giản và trực tiếp.

Thử nghiệm trông như thế này (các đoạn trích được lấy từ trang dự án):

#!/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

Một bước chạy đơn giản:

$ 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

Kiểm tra cuối cùng cho thấy là "không ổn", nhưng mã thoát là 0 vì đó là a TODO. Người ta cũng có thể thiết lập chi tiết:

$ 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

Đổi tên nó để sử dụng một .ttiện ích mở rộng và đặt nó vào một tthư mục con và bạn có thể sử dụng prove(1)(một phần của Perl) để chạy nó:

$ 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

Đặt OSHT_JUNIThoặc chuyển -jđể tạo ra đầu ra JUnit. JUnit cũng có thể được kết hợp với prove(1).

Tôi đã sử dụng thư viện này cả hai chức năng kiểm tra bằng cách tìm nguồn cung cấp các tệp của chúng và sau đó chạy các xác nhận với IS/ OKvà các phủ định của chúng và các tập lệnh bằng cách sử dụng RUN/ NRUN. Đối với tôi, khung công tác này mang lại nhiều lợi ích nhất với chi phí ít nhất.


1

Tôi đã thử rất nhiều giải pháp được trình bày ở đây, nhưng thấy hầu hết chúng đều cồng kềnh và khó sử dụng, vì vậy tôi đã xây dựng khung thử nghiệm nhỏ của riêng mình: https://github.com/meonlol/t-bash

Nó chỉ là một tệp trong repo mà bạn có thể đơn giản chạy trực tiếp, với một bộ xác nhận kiểu JUnit cơ bản.

Tôi đã sử dụng nó một cách chuyên nghiệp trong một số dự án nội bộ và có thể làm cho các tập lệnh bash của chúng tôi siêu ổn định và chống hồi quy.



0

Hãy xem Outthentic , nó đơn giản, có thể mở rộng bằng nhiều ngôn ngữ (Perl, Python, Ruby, Bash tùy chọn) và khung nền tảng chéo (Linux, Windows) để kiểm tra bất kỳ ứng dụng dòng lệnh nào.


-2

Tôi thấy thật khó để biện minh cho việc sử dụng bash cho các tập lệnh lớn hơn khi Python có những lợi thế to lớn như vậy:

  • Thử / Ngoại trừ cho phép viết các tập lệnh mạnh mẽ hơn với khả năng hoàn tác các thay đổi trong trường hợp có lỗi.
  • Bạn không cần phải sử dụng cú pháp khó hiểu như 'if [ x"$foo" = x"$bar"]; then ... ' dễ bị lỗi.
  • Dễ dàng phân tích cú pháp các tùy chọn và đối số bằng cách sử dụng getopt mô-đun (và có một mô-đun thậm chí còn dễ dàng hơn để phân tích cú pháp đối số, nhưng cái tên này khiến tôi không hiểu).
  • Python cho phép bạn làm việc với danh sách / dict và đối tượng thay vì các chuỗi và mảng cơ bản.
  • Truy cập vào các công cụ ngôn ngữ thích hợp như regex, cơ sở dữ liệu (chắc chắn rằng bạn có thể đưa mọi thứ vào mysqllệnh trong bash, nhưng đó không phải là cách viết mã đẹp nhất).
  • Không cần phải lo lắng về việc sử dụng đúng dạng $*hoặc "$*"hoặc "$@"hoặc $1hoặc "$1", khoảng trắng trong tên tệp không phải là vấn đề, v.v., v.v., v.v.

Bây giờ tôi chỉ sử dụng bash cho những tập lệnh đơn giản nhất.


3
Không phủ nhận thực tế là Python có những lợi thế nhưng điểm thứ hai của bạn không được tốt lắm. So sánh tương tự có thể đã được thực hiện như if [[ $foo = $bar ]]; then .... Điều này vẫn không tốt hơn những gì python cung cấp, nhưng nó tốt hơn những gì bạn đã trình bày.
Shrikant Sharat

8
Một số hệ thống (được nhúng chẳng hạn) không có sẵn python và bạn không thể / không muốn cài đặt thêm nội dung.
Rui Marques

2
Cá nhân tôi thích bash, nhưng đồng ý rằng nó có thể là một chút khó khăn. Bạn thường phải chủ động hơn nhiều trong khi trong Python, bạn có thể giải quyết các lỗi sau khi chúng xuất hiện. Tuy nhiên, bash không có trap(để dọn dẹp / hoàn tác trong trường hợp lỗi) cũng như regex (tức là [[ $1 =~ ^[1-3]{3}$ ]]). Tôi khá chắc chắn rằng cú pháp tối nghĩa mà bạn đã sử dụng liên quan đến các triển khai cũ của nó test, không phải bash. Bash là lựa chọn tuyệt vời để giao tiếp với các công cụ dòng lệnh hiện có ... Thường thì một đường dẫn duy nhất đến awkhoặc grepdễ dàng hơn nhiều so với thay thế Python.
Sáu

1
BTW, mô-đun phân tích cú pháp mà bạn đang đề cập có thể là optparsehoặc người kế nhiệm của nó argparse. Tôi chưa bao giờ thấy bất kỳ ai sử dụng getoptmô-đun, cũng như tôi chưa từng sử dụng nó một cách cá nhân. Các getopttiện ích là tuyệt vời tuy nhiên. Phân tích cú pháp đối số từ shell hoàn toàn không phải là vấn đề khi bạn đã có một mẫu đẹp. Trừ khi bạn đang cố gắng triển khai các lệnh phụ kiểu git hoặc một cái gì đó, nó không có nhiều rắc rối.
Sáu

Python sẽ không chạy ở mọi nơi mà bash có thể tiếp cận. Tôi nói điều đó bởi vì chúng tôi đã thử nghiệm bash so với python, cùng một logic mã và yêu cầu cả hai làm điều gì đó. Bash đã nhập mọi thư mục mà nó có quyền truy cập. Mặt khác, python không thể xử lý một số quyền thư mục và tệp cũng như các thư mục đang tăng và giảm rất nhanh.
vianna77 17/02/16
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.