Skrypty Bash od lat są jednym z podstawowych narzędzi administratorów systemów Linux, inżynierów DevOps oraz programistów automatyzujących codzienne zadania. Ich popularność wynika z prostoty, dostępności i bardzo dobrej integracji z systemem operacyjnym.
Problem pojawia się wtedy, gdy skrypt zaczyna pełnić ważną rolę w infrastrukturze. Automatyczne wdrożenia, backupy, konfiguracja serwerów czy narzędzia CLI muszą działać przewidywalnie. Samo ręczne uruchamianie skryptu po każdej zmianie szybko przestaje być wystarczające.
W takich sytuacjach warto sięgnąć po Bats (Bash Automated Testing System) – lekki framework umożliwiający pisanie automatycznych testów dla skryptów Bash oraz dowolnych aplikacji uruchamianych z terminala.
Czym jest Bats?
Bats jest frameworkiem testowym dla powłoki Bash. Jego głównym założeniem jest możliwość testowania programu tak, jak zrobiłby to użytkownik:
użytkownik
|
v
terminal
|
v
aplikacja CLI
|
v
wynik działania
Test nie musi znać wewnętrznej implementacji programu. Nie interesuje go, czy aplikacja została napisana w Bash, Pythonie, Go czy Rust. Sprawdza jedynie publiczne zachowanie:
- argumenty programu,
- kod zakończenia,
- komunikaty stdout/stderr,
- wygenerowane pliki,
- strukturę katalogów,
- poprawność wyników.
To sprawia, że Bats doskonale nadaje się do testów typu black-box.
Instalacja Bats
Na większości dystrybucji Linux Bats można zainstalować przez menedżer pakietów.
Ubuntu / Debian
sudo apt install bats
Sprawdzenie instalacji:
bats --version
Alternatywnie można zainstalować najnowszą wersję z repozytorium:
git clone https://github.com/bats-core/bats-core.git
cd bats-core
sudo ./install.sh /usr/local
Po instalacji polecenie:
bats
powinno być dostępne globalnie.
Pierwszy test w Bats
Załóżmy, że mamy prosty program:
#!/bin/bash
echo "Hello Linux"
exit 0
Zapisujemy go jako:
hello.sh
Następnie tworzymy katalog testów:
tests/
└── hello_test.bats
Pierwszy test:
@test "Program zwraca poprawny komunikat" {
run ./hello.sh
[ "$status" -eq 0 ]
[ "$output" = "Hello Linux" ]
}
Uruchomienie:
bats tests/
Rezultat:
1 test, 1 success
Bats automatycznie wykrywa wszystkie pliki zakończone rozszerzeniem .bats.
Biblioteki bats-support i bats-assert
Podstawowy Bats jest wystarczający do prostych przypadków, ale w większych projektach warto użyć dodatkowych bibliotek:
- bats-support – dodaje pomocnicze funkcje testowe,
- bats-assert – umożliwia czytelniejsze asercje.
Instalacja:
git clone https://github.com/bats-core/bats-support.git test/libs/bats-support
git clone https://github.com/bats-core/bats-assert.git test/libs/bats-assert
Struktura projektu:
project/
|
├── decoder
|
├── tests/
│ ├── libs/
│ │ ├── bats-support/
│ │ └── bats-assert/
│ |
│ └── decoder_test.bats
W pliku testowym importujemy biblioteki:
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
Teraz możemy pisać bardziej czytelne testy:
@test "Decoder generuje plik CSV" {
run ./decoder \
--input sample.mf4 \
--dbc vehicle.dbc \
--output result.csv
assert_success
assert_output --partial "Decoding completed"
[ -f result.csv ]
}
Zamiast:
[ "$status" -eq 0 ]
otrzymujemy:
assert_success
co jest znacznie łatwiejsze do zrozumienia.
Testowanie aplikacji CLI jako czarnej skrzynki
Załóżmy, że tworzymy narzędzie:
decoder \
--dbc vehicle.dbc \
--input recording.mf4 \
--output data.csv
Test Bats może wyglądać tak:
@test "Dekodowanie poprawnego pliku MDF4" {
run ./decoder \
--dbc tests/data/car.dbc \
--input tests/data/test.mf4 \
--output "$BATS_TEST_TMPDIR/result.csv"
assert_success
assert_file_exist \
"$BATS_TEST_TMPDIR/result.csv"
}
Test sprawdza cały przepływ:
- aplikacja startuje,
- argumenty są poprawne,
- plik MDF4 zostaje odczytany,
- dane są przetworzone,
- wynik zostaje zapisany.
Nie ma znaczenia, że wewnątrz działa Python, biblioteka cantools czy pandas.
Integracja z GitHub Actions
Jedną z największych zalet Bats jest łatwa integracja z CI/CD.
Przykładowy workflow:
name: Tests
on:
push:
branches:
- main
jobs:
bats:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Bats
run: |
sudo apt update
sudo apt install bats
- name: Run tests
run: |
bats tests/
Od tego momentu każdy commit będzie automatycznie sprawdzał poprawność aplikacji.
Porównanie wyników
W przypadku narzędzi generujących dane często stosuje się tak zwane golden files.
Przykład:
tests/
|
├── input/
│ └── sample.mf4
|
├── expected/
│ └── result.csv
|
└── decoder_test.bats
Test:
@test "Wynik dekodowania jest poprawny" {
./decoder \
--input tests/input/sample.mf4 \
--output result.csv
diff \
tests/expected/result.csv \
result.csv
}
Jeżeli format wyjściowy się zmieni, test natychmiast wykryje różnicę.
Bats czy pytest, Go albo Rust?
Wybór zależy od celu.
Jeżeli testujemy bibliotekę lub kod wewnętrzny – framework języka aplikacji będzie lepszy.
Jeżeli testujemy publiczne API programu CLI – Bats jest bardzo dobrym rozwiązaniem.
Najważniejsze zalety:
| Cecha | Bats |
|---|---|
| Testowanie CLI | bardzo dobre |
| Zależność od języka aplikacji | brak |
| Prostota | bardzo wysoka |
| Linux/Unix | idealne środowisko |
| CI/CD | bardzo dobra integracja |
| Testy black-box | doskonałe |
Podsumowanie
Bats jest prostym, ale bardzo skutecznym narzędziem do automatyzacji testów w środowisku Linux. Szczególnie dobrze sprawdza się tam, gdzie aplikacja jest używana przez użytkownika jako polecenie terminalowe.
Dzięki podejściu black-box można testować rzeczywiste zachowanie programu bez uzależniania się od języka programowania, bibliotek czy struktury kodu.
Dla narzędzi CLI, skryptów administracyjnych i aplikacji DevOps Bats stanowi lekki odpowiednik dużych frameworków testowych, oferując jednocześnie prostotę typową dla świata Unix.