2009-06-09 33 views
58

Prawie każdy produkt, nad którym pracowałem przez lata, zawierał pewien poziom skryptów powłoki (lub plików wsadowych, PowerShell itp. W systemie Windows). Mimo że większość kodu napisaliśmy w języku Java lub C++, zawsze wydawało się, że niektóre zadania integracyjne lub instalacyjne zostały lepiej wykonane przy pomocy skryptu powłoki.Testowanie jednostek dla skryptów powłoki

Skrypty powłoki stają się częścią dostarczonego kodu i dlatego muszą być testowane tak jak skompilowany kod. Czy ktokolwiek ma doświadczenie z niektórymi frameworkami testów jednostkowych skryptu powłoki, które są tam dostępne, takimi jak shunit2? Na razie interesuję się głównie skryptami powłoki Linuxa; Chciałbym wiedzieć, jak dobrze uprząż testowa powiela funkcjonalność i łatwość użycia innych frameworków xUnit i jak łatwo jest zintegrować się z systemami do ciągłej kompilacji, takimi jak CruiseControl lub Hudson.

+1

Można również sprawdzić bashtest util: https: // GitHub.com/pahaz/bashtest (jest to prosty sposób pisania testów bash) – pahaz

+0

Roundup formalizuje dla ciebie kilka zadań/tagów. Po przejściu przez garb nauki, jest to całkiem przydatne. Osobiście bardziej podoba mi się podejście haridsv, ponieważ nie wymaga instalowania kolejnego pkg. Zastosowałem to podejście do skryptów powłoki i testów Pythona. – todo

+1

Sprawdź ten przegląd prawie każdego możliwego narzędzia: https://medium.com/wemake-services/testing-bash-applications-85512e7fe2de – sobolevn

Odpowiedz

42

Używam shunit2 dla skryptów powłoki związanych z aplikacją WWW Java/Ruby w środowisku Linux. Jest łatwy w użyciu, a nie dużym odejściem od innych frameworków xUnit.

nie próbowałem integracji z Corector lub Hudson/Jenkins, ale w realizacji ciągłej integracji za pomocą innych środków, jakie napotkał tych problemów:

  • stan Wyjście: Kiedy pakiet test nie powiedzie się, shunit2 nie używa niezerowy status wyjścia w celu powiadomienia o awarii. Musisz albo przeanalizować wyjście shunit2, aby określić pass/fail pakietu, albo zmienić shunit2, aby zachowywał się tak, jak oczekują niektóre nieprzerwane struktury integracyjne, komunikując pass/fail przez status wyjścia.
  • Logi XML: shunit2 nie tworzy logarytmu XML w stylu JUnit.
+0

Pete, jestem bardzo blisko wydania biblioteki testów jednostkowych, która działa dla basha i ksh, bardzo prosta w użyciu. Czy możesz wysłać mi link do logu XML w stylu Junit, żeby zobaczyć, co zawiera? Czy chcesz również uzyskać status wyjścia dla pojedynczego testu niepowodzenia lub na końcu, gdy zakończony, jeśli> 0 test kończy się wynikiem 1? Sposób, w jaki teraz to robię, polega na tym, że istnieje funkcja, którą możesz wywołać, aby uzyskać # testów, które przeszły/zakończyły się niepowodzeniem. –

+0

@EthanPost Nie używam już/wymagają dzienników XML. Możesz znaleźć pomoc, szukając informacji takich jak "xunit xml format". Takie rzeczy: https://xunit.github.io/docs/format-xml-v2.html –

16

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

Oto link do artykułu w README wyjaśniający go w szczegółach.

+1

Roundup również zaleca [konkurs] (https://github.com/citrusbyte/contest) –

20

Roundup przez @ Blake-mizerany brzmi świetnie, i mam z niego skorzystać w przyszłości, ale tutaj jest moje podejście „poor-man” do tworzenia testów jednostkowych:

  • Oddzielna wszystko sprawdzalne jako funkcjonować.
  • Przenieś funkcje do pliku zewnętrznego, na przykład functions.sh i source do skryptu. W tym celu można użyć source `dirname $0`/functions.sh.
  • Pod koniec functions.sh, osadzić swoich przypadków testowych w poniżej jeśli warunek:

    if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then 
    fi 
    
  • Twoje testy są dosłowne wywołania funkcji następuje za pomocą prostych kontroli dla kodów wyjściowych i wartości zmiennych. Chciałbym dodać prostą funkcję użytkową jak poniżej, aby ułatwić napisać:

    function assertEquals() 
    { 
        msg=$1; shift 
        expected=$1; shift 
        actual=$1; shift 
        if [ "$expected" != "$actual" ]; then 
         echo "$msg EXPECTED=$expected ACTUAL=$actual" 
         exit 2 
        fi 
    } 
    
  • Wreszcie uruchomić functions.sh bezpośrednio do wykonywania testów.

Oto przykład, aby pokazać podejście:

#!/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 $? 
    ) 
+1

Miło, dzięki - naprawdę podobnie jak podejście do programowania w skryptach powłoki. –

+0

Bardzo dobra obserwacja: "Oddziel wszystko, co można przetestować jako funkcję". Jest to ważne, nawet jeśli nie (jeszcze) napisałeś testu na to. Jest to główny czynnik poprawiający czytelność kodu. Kilka lat temu zacząłem pisać mój skrypt (ksh) zgodnie z tą zasadą. Napisz wszystko jako funkcję. –

+0

@HenkLangeveld Czy "exit 0" nie spowoduje, że "sourcee" (ten, z którego pochodzi) również zostanie zakończone? Myślę, że szukasz "powrotu" tutaj. – haridsv

6

oprócz roundup i shunit2 mój przegląd jednostkowych shell narzędzi testowania zawarte również assert.sh i shelltestrunner.

W większości zgadzam się z autorską krytyką shunit2 (część z nich jest subiektywna), więc wykluczyłem shunit2 po zapoznaniu się z dokumentacją i przykładami. Chociaż wyglądał znajomo, mając pewne doświadczenie z jUnit.

Moim zdaniem shelltestrunner jest najbardziej oryginalnym narzędziem, na które patrzyłem, ponieważ używa prostej składni deklaratywnej do definicji przypadku testowego. Jak zwykle, każdy poziom abstrakcji daje pewną wygodę kosztem pewnej elastyczności. Mimo, że prostota jest atrakcyjna, znalazłem narzędzie zbyt ograniczone do tego, co miałem, głównie z powodu braku możliwości zdefiniowania działań setup/tearDown (na przykład, manipulowanie plikami wejściowymi przed testem, usuwanie plików stanu po teście itp.).

Początkowo byłem nieco zdezorientowany, że assert.sh pozwala tylko potwierdzać stan wyjścia lub wyjścia, podczas gdy ja potrzebowałem obu. Wystarczająco długo, aby napisać kilka przypadków testowych za pomocą podsumowania. Wkrótce jednak okazało się, że tryb zaokrąglania jest niewygodny, ponieważ spodziewany jest niezerowy status wyjścia, w niektórych przypadkach jako sposób komunikacji z wynikiem dodatnim do standardowego, co powoduje, że przypadek testowy nie powiedzie się we wspomnianym trybie. One of the samples przedstawia rozwiązanie:

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

Ale co jeśli trzeba zarówno niezerowym wyjścia i wyjście? Mógłbym oczywiście przed wywołaniem set +e i po lub set +e dla całego przypadku testowego. Ale jest to sprzeczne z zasadą łapanki "Everything is an Assertion". Czułem, że zaczynam pracować przeciwko temu narzędziu.

Wtedy zdałem sobie sprawę „wadę” The assert.sh za zezwoleniem tylko dochodzić zarówno stanu wyjścia i wyjścia właściwie nie problem, jak można po prostu przejść w test z wyrażenia złożonego tak

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

Ponieważ moje potrzeby były naprawdę podstawowe (uruchomić zestaw testów, wyświetlić, że wszystko poszło dobrze lub co nie), podobała mi się prostota assert.sh, więc to właśnie wybrałem.

2

Po wyszukaniu prostej struktury testowej jednostki dla powłoki, która mogłaby generować wyniki XML dla Jenkinsa i nie znalazła niczego, napisałem jedną.

Jest na sourceforge - nazwa projektu to jshu.

http://sourceforge.net/projects/jshu

23

Zastanawiasz się, dlaczego nikt nie wspomniał BATS. Jest aktualny i zgodny z TAP.

opisać:

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

+1 za BATY! Sądząc po metrykach Githuba (12 autorów, prawie 2000 gwiazdek), jest to narzędzie najczęściej wybierane przez użytkowników jako testowy test bash xUnit. –

+1

+1: Użyłem BATS przed chwilą i nie byłem całkowicie przytłoczony. Znalazłeś ten znakomity (niezależny?) Dokument [Pierwsze kroki] (https://medium.com/@pimterry/testing-your-shell-scripts-with-bats-abfca9bdc5b9) dzisiaj, a potem przejrzałem go i jestem teraz całkowicie sprzedany na BATS . – ssc