W latach 60-tych, to było uważane za podstawową dobrą praktykę w inżynierii oprogramowania, aby testować swój kod tak jak go napisałeś. Pionierzy rozwoju oprogramowania w tej epoce byli zwolennikami różnych poziomów testowania; niektórzy opowiadali się za testowaniem „jednostkowym”, inni nie, ale wszyscy uznawali wagę testowania kodu.
Testy wykonywalne mogły być po raz pierwszy wprowadzone przez Margaret Hamilton w projekcie Apollo w połowie lat 60-tych, gdzie stworzyła typ sprawdzania wykonywalności, który teraz nazywamy „statyczną analizą kodu”. Nazywała je „oprogramowaniem wyższego rzędu”, przez co rozumiała oprogramowanie, które działa raczej w stosunku do innego oprogramowania niż bezpośrednio w stosunku do domeny problemu. Jej oprogramowanie wyższego rzędu badało kod źródłowy w poszukiwaniu wzorców, o których wiadomo było, że prowadzą do problemów z integracją.
Do 1970 roku ludzie w dużej mierze zapomnieli o testowaniu wykonywalności. Jasne, ludzie uruchamiali aplikacje i sprawdzali je tu i tam ręcznie, ale tak długo jak budynek nie płonął wokół nich, uważali, że kod jest „wystarczająco dobry”. Rezultatem było ponad 35 lat kodu w produkcji na całym świecie, który jest nieodpowiednio przetestowany, a w wielu przypadkach nie działa całkowicie zgodnie z przeznaczeniem, lub w sposób, który zadowala klientów.
Pomysł testowania przez programistów w trakcie pracy powrócił w połowie lat 90-tych, chociaż do chwili obecnej większość programistów nadal tego nie robi. Inżynierowie infrastruktury i administratorzy systemów testują swoje skrypty jeszcze mniej sumiennie niż programiści testują swój kod aplikacji.
Jako że wkraczamy w erę, w której szybkie wdrażanie skomplikowanych rozwiązań składających się z wielu autonomicznych komponentów staje się normą, a infrastuktury „chmurowe” wymagają od nas zarządzania tysiącami maszyn wirtualnych i kontenerów typu come-and-go w skali, której nie da się opanować metodami ręcznymi, nie można ignorować znaczenia wykonywalnych, zautomatyzowanych testów i sprawdzania w całym procesie rozwoju i dostarczania, nie tylko dla programistów aplikacji, ale dla wszystkich osób zaangażowanych w pracę IT.
Wraz z nadejściem devops (cross-pollining development and operations skills, methods, and tools) i trendów takich jak „infrastruktura jako kod” i „automatyzuj wszystko”, testowanie jednostkowe stało się podstawową umiejętnością dla programistów, testerów, administratorów systemu i inżynierów infrastruktury.
W tej serii postów, przedstawimy ideę testowania jednostkowego skryptów powłoki, a następnie zbadamy kilka frameworków testów jednostkowych, które mogą pomóc uczynić to zadanie praktycznym i trwałym w skali.
Inną praktyką, która może być nieznana wielu inżynierom infrastruktury jest kontrola wersji. W dalszej części tej serii poruszymy temat systemów kontroli wersji i przepływów pracy, których używają programiści aplikacji, a które mogą być skuteczne i użyteczne również dla inżynierów infrastruktury.
Skrypt do testowania
Vivek Gite opublikował przykładowy skrypt powłoki do monitorowania użycia dysków i generowania powiadomień e-mail, gdy pewne systemy plików przekroczą pewien próg. Jego artykuł znajduje się tutaj: https://www.cyberciti.biz/tips/shell-script-to-watch-the-disk-space.html. Użyjmy go jako obiektu testowego.
Wstępna wersja jego skryptu, z dodaniem opcji -P w poleceniu df, aby zapobiec łamaniu linii na wyjściu, jak zasugerował Per Lindahl, wygląda następująco:
#!/bin/shdf -HP | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print " " }' | while read output;do usep=$(echo $output | awk '{ print }' | cut -d'%' -f1 ) partition=$(echo $output | awk '{ print }' ) if ; then echo "Running out of space \"$partition ($usep%)\" on $(hostname) as on $(date)" | mail -s "Alert: Almost out of disk space $usep%" [email protected] fidone
Vivek udoskonala skrypt poza tym punktem, ale ta wersja posłuży do celów niniejszego postu.
Automatyzowane kontrole funkcjonalne
Kilka zasad dotyczących zautomatyzowanych kontroli funkcjonalnych, niezależnie od tego czy sprawdzamy kod aplikacji, skrypt czy jakikolwiek inny rodzaj oprogramowania:
- kontrola musi przebiegać identycznie za każdym razem, bez konieczności ręcznego dostrajania, aby przygotować się do każdego uruchomienia; i
- wynik nie może być podatny na zmiany w środowisku wykonawczym, lub danych, lub innych czynników zewnętrznych w stosunku do testowanego kodu.
Pass, Fail, and Error
Możesz zauważyć, że jest możliwe, że skrypt w ogóle nie zostanie uruchomiony. Jest to normalne dla każdego rodzaju testów jednostkowych dla każdego rodzaju aplikacji. Możliwe są trzy wyniki, a nie dwa:
- Testowany kod wykazuje oczekiwane zachowanie
- Testowany kod działa, ale nie wykazuje oczekiwanego zachowania
- Testowany kod nie działa
Dla celów praktycznych, trzeci wynik jest taki sam jak drugi; będziemy musieli dowiedzieć się, co poszło nie tak i to naprawić. Tak więc, generalnie myślimy o tych rzeczach jako binarnych: Pass or fail.
What Should We Check?
W tym przypadku interesuje nas sprawdzenie, czy skrypt zachowa się zgodnie z oczekiwaniami, biorąc pod uwagę różne wartości wejściowe. Nie chcemy zanieczyszczać naszych testów jednostkowych żadną inną weryfikacją poza tą.
Przeglądając testowany kod, widzimy, że gdy użycie dysku osiągnie próg 90%, skrypt wywołuje pocztę, aby wysłać powiadomienie do administratora systemu.
Podtrzymując ogólnie przyjętą dobrą praktykę sprawdzania jednostek, chcemy zdefiniować osobne przypadki, aby zweryfikować każde zachowanie, którego oczekujemy dla każdego zestawu warunków początkowych.
Zakładając nasz kapelusz „testera”, widzimy, że jest to rodzaj warunku brzegowego. Nie musimy sprawdzać wielu różnych procentów użycia dysku indywidualnie. Musimy tylko sprawdzić zachowanie na granicach. W związku z tym, minimalny zestaw przypadków, który zapewni sensowne pokrycie będzie następujący:
- Wysyła e-mail, gdy użycie dysku osiągnie próg
- Nie wysyła e-maila, gdy użycie dysku jest poniżej progu
Czego nie powinniśmy sprawdzać?
Podtrzymując ogólnie przyjętą dobrą praktykę izolowania testów jednostkowych, chcemy się upewnić, że każdy z naszych przypadków może zawieść z dokładnie jednego powodu: Oczekiwane zachowanie nie ma miejsca. W miarę możliwości chcemy skonfigurować nasze testy tak, aby inne czynniki nie spowodowały, że dany przypadek się nie powiedzie.
Nie zawsze może być opłacalne (lub nawet możliwe) zagwarantowanie, że czynniki zewnętrzne nie wpłyną na nasze zautomatyzowane testy. Zdarzają się sytuacje, w których nie możemy kontrolować elementu zewnętrznego, lub gdy wymaga to więcej czasu, wysiłku i kosztów niż wartość sprawdzenia, i/lub dotyczy niejasnego przypadku brzegowego, który ma bardzo małe prawdopodobieństwo wystąpienia lub bardzo mały wpływ, gdy wystąpi. Jest to kwestia Twojego profesjonalnego osądu. Jako ogólną zasadę, staraj się unikać tworzenia zależności od czynników poza zakresem testowanego kodu.
Nie musimy sprawdzać, czy polecenia df, grep, awk, cut i mail działają. To jest poza zakresem naszych celów. Ktokolwiek opiekuje się tymi narzędziami jest za to odpowiedzialny.
Chcemy wiedzieć, czy wyjście z polecenia df nie jest przetwarzane w sposób, jakiego oczekujemy od grep lub awk. Dlatego chcemy, aby prawdziwe polecenia grep i awk były uruchamiane w naszych testach, na podstawie danych wyjściowych z polecenia df, które pasują do intencji każdego przypadku testowego. To jest w zakresie, ponieważ argumenty wiersza poleceń do df są częścią skryptu, a skrypt jest testowanym kodem.
To oznacza, że będziemy potrzebowali fałszywej wersji polecenia df do użycia w naszych testach jednostkowych. Ten rodzaj fałszywego komponentu jest często nazywany makietą. Makieta zastępuje prawdziwy komponent i dostarcza predefiniowane dane wyjściowe, aby kontrolować zachowanie systemu, dzięki czemu możemy sprawdzić zachowanie testowanego kodu w sposób niezawodny.
Widzimy, że skrypt wysyła powiadomienie e-mail, gdy system plików osiągnie progowy poziom użycia. Nie chcemy, aby nasze testy jednostkowe wysyłały masę bezużytecznych maili, więc będziemy chcieli wykpić również komendę mail.
Ten skrypt jest dobrym przykładem do zilustrowania wykpiwania tych komend, ponieważ zrobimy to w inny sposób dla mail niż dla df.
Wykpiwanie komendy df
Skrypt zbudowany jest wokół komendy df. Odpowiednia linia w skrypcie to:
df -HP | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print " " }'
Jeśli uruchomisz tylko df -HP, bez pipingowania do grep, zobaczysz wyjście podobne do tego:
Filesystem Size Used Avail Use% Mounted onudev 492M 0 492M 0% /devtmpfs 103M 6.0M 97M 6% /run/dev/sda1 20G 9.9G 9.2G 52% /tmpfs 511M 44M 468M 9% /dev/shmtmpfs 5.3M 0 5.3M 0% /run/locktmpfs 511M 0 511M 0% /sys/fs/cgrouptmpfs 103M 8.2k 103M 1% /run/user/1000
Komendy grep i awk zmniejszają wyjście do tego:
0% udev52% /dev/sda1
Musimy kontrolować wyjście z df, aby napędzać nasze przypadki testowe. Nie chcemy, aby wynik sprawdzania różnił się w zależności od rzeczywistego wykorzystania dysku w systemie, w którym wykonujemy zestaw testów. Nie sprawdzamy użycia dysku; sprawdzamy logikę skryptu. Kiedy skrypt zostanie uruchomiony na produkcji, będzie sprawdzał użycie dysku. To, co tutaj robimy, służy walidacji, a nie operacjom produkcyjnym. Dlatego potrzebujemy fałszywego lub „szyderczego” polecenia df, za pomocą którego możemy wygenerować „dane testowe” dla każdego przypadku.
Na platformie *nix możliwe jest zastąpienie prawdziwego polecenia df przez zdefiniowanie aliasu. Chcemy, by polecenie aliasowe emitowało wartości testowe w tym samym formacie, co wyjście z df -HP. Oto jeden ze sposobów na zrobienie tego (to wszystko jest jednym wierszem; poniżej jest rozbite dla czytelności):
alias df="shift;echo -e 'Filesystem Size Used Avail Use% Mounted on'; echo -e 'tempfs 511M 31M 481M 6% /dev/shm'; echo -e '/dev/sda1 20G 9.9G 9.2G 52% /'"
Przesunięcie pomija argument ’-HP’ podczas uruchamiania skryptu, tak że system nie będzie narzekał, że -HP jest nieznanym poleceniem. Aliasowane polecenie df emituje dane wyjściowe w takiej samej postaci jak df -HP.
Wartości testowe są przesyłane do grep, a następnie awk podczas wykonywania skryptu, więc kpimy tylko z minimum niezbędnego do kontrolowania naszych przypadków testowych. Chcemy, aby nasz przypadek testowy był jak najbardziej zbliżony do „prawdziwej rzeczy”, abyśmy nie otrzymali fałszywych pozytywów.
Mocki tworzone za pomocą biblioteki szyderczej mogą zwracać predefiniowaną wartość, gdy są wywoływane. Nasze podejście do wyśmiewania polecenia df odzwierciedla funkcję wyśmiewania; określamy predefiniowane dane wyjściowe, które mają być zwracane za każdym razem, gdy testowany kod wywoła df.
Wyśmiewanie polecenia mail
Chcemy wiedzieć, czy skrypt próbuje wysłać wiadomość e-mail w odpowiednich warunkach, ale nie chcemy, aby wysyłał prawdziwą wiadomość e-mail gdziekolwiek. Dlatego chcemy aliasować komendę mail, tak jak zrobiliśmy to wcześniej z komendą df. Musimy skonfigurować coś, co będziemy mogli sprawdzić po każdym przypadku testowym. Jedną z możliwości jest zapisanie wartości do pliku, gdy wywoływana jest poczta, a następnie sprawdzenie tej wartości w naszym przypadku testowym. Jest to pokazane w poniższym przykładzie. Inne metody są również możliwe.
Mocki utworzone za pomocą biblioteki szyderczej mogą liczyć ile razy są wywoływane przez testowany kod, a my możemy zapewnić oczekiwaną liczbę wywołań. Nasze podejście do wyśmiewania polecenia mail odzwierciedla tę funkcję makiety; jeśli tekst „mail” jest obecny w pliku mailsent po uruchomieniu skryptu diskusage.sh, oznacza to, że skrypt wywołał polecenie mail.
Pattern for Running Automated Checks
Automatyczne lub wykonywalne kontrole na dowolnym poziomie abstrakcji, dla dowolnego rodzaju aplikacji lub skryptu, w dowolnym języku, zazwyczaj składają się z trzech kroków. Zwykle noszą one nazwy:
- Arrange
- Act
- Assert
Powodem tego jest prawdopodobnie to, że wszyscy uwielbiają aliterację, szczególnie na literę A, jako że samo słowo „aliteracja” zaczyna się od litery A.
Cokolwiek by to nie było, w kroku aranżacji ustalamy warunki wstępne dla naszego przypadku testowego. W kroku act wywołujemy testowany kod. W kroku assert deklarujemy rezultat, który spodziewamy się zobaczyć.
Gdy używamy frameworka testowego lub biblioteki, narzędzie obsługuje krok assert ładnie dla nas, tak że nie musimy kodować dużo kłopotliwej logiki if/else w naszych zestawach testów. W naszym początkowym przykładzie, nie używamy frameworka testowego ani biblioteki, więc sprawdzamy wyniki każdego przypadku za pomocą bloku if/else. W następnej odsłonie pobawimy się szkieletami testów jednostkowych dla języków powłoki i zobaczymy, jak to wygląda.
Oto nasz prymitywny, ale skuteczny skrypt testowy do testowania skryptu powłoki Viveka, który nazwaliśmy diskusage.sh:
#!/bin/bashshopt -s expand_aliases# Before allalias mail="echo 'mail' > mailsent;false"echo 'Test results for diskusage.sh' > test_resultstcnt=0# It does nothing when disk usage is below 90%# Before (arrange)alias df="echo 'Filesystem Size Used Avail Use% Mounted on';echo '/dev/sda2 100G 89.0G 11.0G 89% /'"echo 'no mail' > mailsent# Run code under test (act). ./diskusage.sh# Check result (assert)((tcnt=tcnt+1))if ]; then echo "$tcnt. FAIL: Expected no mail to be sent for disk usage under 90%" >> test_resultselse echo "$tcnt. PASS: No action taken for disk usage under 90%" >> test_resultsfi # It sends an email notification when disk usage is at 90%alias df="echo 'Filesystem Size Used Avail Use% Mounted on';echo '/dev/sda1 100G 90.0G 10.0G 90% /'"echo 'no mail' > mailsent. ./diskusage.sh((tcnt=tcnt+1))if ]; then echo "$tcnt. PASS: Notification was sent for disk usage of 90%" >> test_resultselse echo "$tcnt. FAIL: Disk usage was 90% but no notification was sent" >> test_resultsfi # After allunalias dfunalias mail# Display test results cat test_results
Oto przewodnik po skrypcie testowym.
Po pierwsze, widzisz, że używamy basha do testowania zwykłego, starego pliku .sh. To jest całkowicie w porządku. Nie jest to konieczne, ale jest w porządku.
Następnie, widzisz polecenie shopt. Spowoduje to, że powłoka rozszerzy nasze testowe aliasy, gdy podpowłoka zostanie wywołana w celu uruchomienia skryptu diskusage.sh. W większości przypadków użycia, nie przekazalibyśmy aliasów do podpowłoki, ale testy jednostkowe są wyjątkiem.
Komentarz, „Przed wszystkim”, jest dla ludzi, którzy są zaznajomieni z frameworkami testów jednostkowych, które mają polecenia ustawiające i usuwające. Często nazywają się one „przed” i „po”, i zwykle jest jedna para, która obejmuje cały zestaw testów i inna para, która jest wykonywana indywidualnie dla każdego przypadku testowego.
Chcieliśmy pokazać, że definiowanie aliasu dla poczty, inicjalizacja pliku z wynikami testów i inicjalizacja licznika przypadków testowych są wykonywane dokładnie raz, na początku zestawu testów. Tego typu rzeczy są normalne w wykonywalnych zestawach testowych. Fakt, że testujemy skrypt powłoki zamiast programu użytkowego, nie zmienia tego faktu.
Następny komentarz, „To nic nie robi…” wskazuje początek naszego pierwszego pojedynczego przypadku testowego. Większość frameworków testów jednostkowych oferuje możliwość nadania nazwy każdemu przypadkowi, abyśmy mogli śledzić, co się dzieje i aby inne narzędzia mogły wyszukiwać, filtrować i wyodrębniać przypadki testowe z różnych powodów.
Następny komentarz brzmi: „Before (arrange)”. Ten reprezentuje ustawienia, które odnoszą się tylko do tego jednego przypadku testowego. Ustawiamy alias df tak, aby emitował dane wyjściowe, których potrzebujemy dla tego konkretnego przypadku. Zapisujemy również tekst „brak poczty” do pliku. W ten sposób będziemy mogli stwierdzić, czy skrypt diskusage.sh próbował wysłać e-mail z powiadomieniem.
Następnym krokiem jest wykonanie testowanego kodu. W tym przypadku oznacza to uruchomienie samego skryptu diskusage.sh.
Teraz wykonujemy krok assert, który w tym przykładzie wykonujemy w trudny sposób, ponieważ nie wprowadziliśmy jeszcze frameworka testowego. Inkrementujemy licznik testów, abyśmy mogli ponumerować przypadki testowe w pliku z wynikami. W przeciwnym razie, gdybyśmy mieli dużą liczbę przypadków, trudno byłoby się zorientować, które z nich zawiodły. Zajmują się tym za nas frameworki testowe.
Alias, który zdefiniowaliśmy dla polecenia mail, zapisuje tekst 'mail’ do pliku mailsent. Jeśli diskusage.sh wywoła mail, wtedy plik mailsent będzie zawierał 'mail’ zamiast początkowej wartości 'no mail’. Możesz zobaczyć, jakie są warunki zaliczenia i niezaliczenia, czytając ciągi znaków w pliku z wynikami testu.
Zaczynając od komentarza „It sends an email notification…” powtarzamy kroki arrange, act, assert dla kolejnego przypadku testowego. Tym razem nasze fałszywe polecenie df będzie emitowało inne dane, aby wymusić inne zachowanie testowanego kodu.
Gdzie pojawia się komentarz „After all”, sprzątamy po sobie, eliminując definicje, które stworzyliśmy w konfiguracji „Before all” na górze skryptu testowego.
Na koniec, wyrzucimy zawartość pliku test_results, abyśmy mogli zobaczyć, co uzyskaliśmy. Wygląda to tak:
Test results for diskusage.sh1. PASS: No action taken for disk usage under 90%2. PASS: Notification was sent for disk usage of 90%
Why Use a Test Framework/Library?
Właśnie napisaliśmy kilka testów jednostkowych dla skryptu powłoki bez użycia frameworka testowego, biblioteki szyderczej czy biblioteki asercji. Odkryliśmy, że polecenia systemowe mogą być wyśmiewane przez definiowanie aliasów (przynajmniej w systemach *nix), że asercje mogą być zaimplementowane jako instrukcje warunkowe, a podstawowa struktura testu jednostkowego jest łatwa do ustawienia ręcznie.
Nie było trudno zrobić to bez frameworka czy biblioteki. Jakie są więc korzyści?
Szkielety testowe i biblioteki upraszczają i standaryzują kod testowy oraz umożliwiają tworzenie znacznie bardziej czytelnych zestawów testów niż ręcznie tworzone skrypty zawierające wiele instrukcji warunkowych. Niektóre biblioteki zawierają przydatne dodatkowe funkcje, takie jak możliwość wychwytywania wyjątków lub możliwość pisania przypadków testowych sterowanych tabelami i danymi. Niektóre są dostosowane do wspierania konkretnych produktów interesujących inżynierów infrastruktury, takich jak Chef i Puppet. A niektóre zawierają funkcjonalność śledzenia pokrycia kodu i/lub formatowania wyników testów w formie możliwej do skonsumowania przez narzędzia w potoku CI/CD, lub przynajmniej przeglądarkę internetową.
Unit Test Frameworks for Scripts
W tej serii będziemy badać kilka frameworków testów jednostkowych dla skryptów powłoki i języków skryptowych. Oto przegląd:
- shunit2 jest bardzo solidnym projektem Open Source z dziesięcioletnią historią. Pierwotnie stworzony przez Kate Ward, Site Reliability Engineer i Manager w Google z siedzibą w Zurychu, jest aktywnie rozwijany i wspierany przez zespół sześciu osób. Od skromnych początków jako punktowe rozwiązanie do testowania biblioteki logowania dla skryptów powłoki, został celowo rozwinięty w uniwersalny framework testów jednostkowych, który obsługuje wiele języków powłoki i systemów operacyjnych. Zawiera wiele użytecznych funkcji wykraczających poza proste asercje, włączając w to wsparcie dla testów sterowanych danymi i tabelami. Używa tradycyjnego stylu asercji „assertThat”. Strona projektu zawiera doskonałą dokumentację. Dla testów jednostkowych ogólnego przeznaczenia dla skryptów powłoki, jest to moja najlepsza rekomendacja.
- BATS (Bash Automated Testing System) jest frameworkiem testów jednostkowych dla basha. Został on stworzony przez Sama Stephensona około siedem lat temu i miał kilkunastu współtwórców. Ostatnia aktualizacja miała miejsce cztery lata temu, ale nie ma się czym przejmować, gdyż tego typu narzędzia nie wymagają częstych aktualizacji czy konserwacji. BATS bazuje na protokole TAP (Test Anything Protocol), który definiuje spójny, tekstowy interfejs pomiędzy modułami w dowolnej wiązce testowej. Pozwala on na czystą, spójną składnię w przypadkach testowych, choć nie wydaje się, by dodawał wiele cukru składniowego poza prostymi instrukcjami basha. Na przykład, nie ma specjalnej składni dla asercji; piszesz komendy bash do testowania wyników. Mając to na uwadze, jego główna wartość może leżeć w organizowaniu zestawów testów i przypadków w logiczny sposób. Zauważ również, że pisanie skryptów testowych w bashu nie przeszkadza nam w testowaniu skryptów niebashowych; zrobiliśmy to wcześniej w tym wpisie. Fakt, że składnia BATS jest tak bliska zwykłej składni basha, daje nam dużą elastyczność w obsłudze różnych języków powłoki w naszych zestawach testów, za ewentualny koszt czytelności (w zależności od tego, co uważasz za „czytelne”; zamierzona publiczność tego wpisu prawdopodobnie uważa składnię zwykłego języka powłoki za całkiem czytelną). Jedną szczególnie interesującą cechą (moim zdaniem) jest to, że można skonfigurować swój edytor tekstu z podświetlaniem składni dla BATS, jak udokumentowano na wiki projektu. Emacs, Sublime Text 2, TextMate, Vim i Atom były obsługiwane w momencie pisania tego postu.
- zunit (nie ten IBM-owski, ten drugi) to framework testów jednostkowych dla zsh, opracowany przez Jamesa Dinsdale’a. Strona projektu podaje, że zunit został zainspirowany przez BATS, i zawiera bardzo użyteczne zmienne $state, $output, i $lines. Ale posiada również definitywną składnię asercji, która podąża za wzorcem, „assert actual matches expected”. Każdy z tych frameworków posiada pewne unikalne cechy. Interesującą cechą ZUnit, moim zdaniem, jest to, że oznaczy każdy przypadek testowy, który nie zawiera asercji jako „ryzykowny”. Można to zmienić i zmusić przypadki do uruchomienia, ale domyślnie framework pomaga pamiętać o dołączeniu asercji do każdego przypadku testowego.
- bash-spec jest behawioralnym frameworkiem testowym, który obsługuje tylko bash (lub przynajmniej był testowany tylko ze skryptami bash). Jest to mój skromny projekt poboczny, który istnieje od ponad czterech lat i ma kilku „prawdziwych” użytkowników. Nie jest on zbytnio aktualizowany, ponieważ obecnie robi to, do czego został stworzony. Jednym z celów projektu było wykorzystanie funkcji basha w „płynnym” stylu. Funkcje są wywoływane sekwencyjnie, każda przekazuje całą listę argumentów do następnej po zużyciu tylu argumentów, ile potrzebuje do wykonania swojego zadania. Rezultatem jest czytelny zestaw testów, zawierający stwierdzenia takie jak „expect package-name to_be_installed” i „expect arrayname not to_contain value”. Kiedy używamy go do tworzenia skryptów w oparciu o testy, jego konstrukcja ma tendencję do prowadzenia programisty do pisania funkcji, które wspierają ideę „modularności” lub „pojedynczej odpowiedzialności” lub „separacji obaw” (nazwij to jak chcesz), co skutkuje łatwością utrzymania i łatwością ponownego użycia funkcji. „Styl behawioralny” oznacza, że asercje przyjmują formę „oczekuj, że to będzie pasować do tego.”
- korn-spec jest portem bash-spec dla powłoki korn.
- Pester jest frameworkiem testów jednostkowych z wyboru dla Powershell. Powershell wygląda i czuje się bardziej jak język programowania aplikacji niż czysto skryptowy język, a Pester oferuje w pełni spójne doświadczenie dewelopera. Pester jest dostarczany z systemem Windows 10 i może być zainstalowany na każdym innym systemie, który obsługuje Powershell. Posiada rozbudowaną bibliotekę asercji, wbudowane wsparcie dla szyderstwa i zbiera metryki pokrycia kodu.
- ChefSpec opiera się na rspec, aby zapewnić behawioralne ramy testowe dla receptur Chef. Chef jest aplikacją Ruby, a ChefSpec w pełni wykorzystuje możliwości rspec plus wbudowane wsparcie dla funkcjonalności specyficznych dla Chef.
- rspec-puppet jest behawioralnym frameworkiem dla Puppet, funkcjonalnie podobnym do ChefSpec.
.