Communitygithub.com

Jamie-BitFlight/bash-testing

Dieses Skill sollte verwendet werden, wenn der Nutzer nach 'Bash-Skript testen', 'Shell-Tests schreiben', 'shunit2 verwenden', 'shellspec verwenden', 'Test-Suite für Bash erstellen' fragt oder Unit-Tests, Test-Frameworks, Mocking oder testgetriebene Entwicklung für Shell-Skripte erwähnt.

Was ist bash-testing?

Dieses Skill bietet eine umfassende Anleitung zum Testen von Bash-Shell-Skripten mit den Frameworks shunit2 und shellspec. Es behandelt die Installation, grundlegende Teststrukturen, spezifische Assertion- und Matcher-Bibliotheken, Mocking-Techniken sowie Best Practices für isolierte und interaktive Tests. Der Skill unterstützt Entwickler dabei, Testszenarien für Exit-Codes, stdout/stderr, Fixtures und interaktive Eingaben zu schreiben und auszuführen. Er ist plattformunabhängig und sowohl für kleine Unit-Tests (shunit2) als auch für verhaltensorientierte Spezifikationen komplexer Projekte (shellspec) geeignet.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Jamie-BitFlight/claude_skills/tree/main/plugins/bash-development/skills/bash-testing

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Bash-Testen

Test-Frameworks und -Muster für Shell-Skripte, mit Fokus auf shunit2 und shellspec.

Framework-Auswahl

FrameworkStärkenAm besten geeignet für
shunit2xUnit-Stil, einfach, portabelUnit-Tests, Funktions-Tests
shellspecBDD-Stil, modern, umfangreichVerhaltensspezifikationen, ganze Projekte

shunit2

Installation

# Direkter Download
curl -L https://github.com/kward/shunit2/raw/master/shunit2 -o shunit2

# Oder über Paketmanager
apt install shunit2
brew install shunit2

Grundlegende Teststruktur

#!/usr/bin/env bash

# Das zu testende Skript einbinden
source ./my_script.sh

# Testfunktionen beginnen mit test
test_addition() {
    result=$(add 2 3)
    assertEquals "2 + 3 sollte 5 ergeben" "5" "$result"
}

test_string_output() {
    result=$(greet "World")
    assertEquals "Hallo, Welt" "$result"
}

test_file_creation() {
    create_temp_file
    assertTrue "Temp-Datei sollte existieren" "[ -f /tmp/testfile ]"
}

test_exit_code() {
    validate_input "valid"
    assertEquals "Sollte 0 für gültige Eingabe zurückgeben" 0 $?
}

# Setup und Teardown
oneTimeSetUp() {
    # Wird einmal vor allen Tests ausgeführt
    export TEST_DIR=$(mktemp -d)
}

oneTimeTearDown() {
    # Wird einmal nach allen Tests ausgeführt
    rm -rf "$TEST_DIR"
}

setUp() {
    # Wird vor jedem Test ausgeführt
    cd "$TEST_DIR"
}

tearDown() {
    # Wird nach jedem Test ausgeführt
    rm -f "$TEST_DIR"/*
}

# shunit2 einbinden
source shunit2

shunit2-Assertionen

# Gleichheit
assertEquals [Nachricht] erwartet aktuell
assertNotEquals [Nachricht] unerwartet aktuell

# Null/Leer
assertNull [Nachricht] wert
assertNotNull [Nachricht] wert

# Boolesch/Status
assertTrue [Nachricht] bedingung
assertFalse [Nachricht] bedingung

# Gleiche Referenz (String-Vergleich)
assertSame [Nachricht] erwartet aktuell
assertNotSame [Nachricht] unerwartet aktuell

# Enthält (im String)
assertContains [Nachricht] container inhalt

# Exit-Status
assertEquals 0 $?

Funktionen isoliert testen

Codebeispiele

#!/usr/bin/env bash
# test_my_functions.sh

source ./my_functions.sh

test_calculate_sum_empty() {
    result=$(calculate_sum)
    assertEquals "Leere Summe sollte 0 sein" "0" "$result"
}

test_calculate_sum_single() {
    result=$(calculate_sum 5)
    assertEquals "5" "$result"
}

test_calculate_sum_multiple() {
    result=$(calculate_sum 1 2 3 4 5)
    assertEquals "15" "$result"
}

test_validate_email_valid() {
    validate_email "[email protected]"
    assertTrue "Gültige E-Mail sollte bestehen" $?
}

test_validate_email_invalid() {
    validate_email "not-an-email"
    assertFalse "Ungültige E-Mail sollte fehlschlagen" $?
}

source shunit2

shellspec

Installation

# Über curl
curl -fsSL https://git.io/shellspec | sh

# Über Homebrew
brew install shellspec

# Über Paketmanager
apt install shellspec

Verzeichnisstruktur

project/
├── lib/
│   └── functions.sh
├── spec/
│   ├── spec_helper.sh
│   ├── functions_spec.sh
│   └── support/
│       └── fixtures/
└── .shellspec

Konfiguration (.shellspec)

--require spec_helper
--format documentation
--color

Grundlegende Spec-Struktur

Codebeispiele

shellspec-Matcher

# Ausgabe-Matcher
The output should eq "exakte Übereinstimmung"
The output should include "teilweise"
The output should start with "präfix"
The output should end with "suffix"
The output should match pattern "*glob*"
The output should be blank

# Status-Matcher
The status should be success    # exit 0
The status should be failure    # exit ungleich 0
The status should eq 1          # spezifischer Code

# Variablen-Matcher
The variable VAR should eq "wert"
The variable VAR should be defined
The variable VAR should be undefined

# Datei-Matcher
The file "pfad" should be exist
The file "pfad" should be file
The file "pfad" should be directory
The file "pfad" should be readable

# Pfad-Matcher
The path "datei.txt" should be exist

Mocking in shellspec

Describe 'deploy-Funktion'
  # Externen Befehl mocken
  curl() {
    echo "gemockte Antwort"
    return 0
  }

  It 'ruft API-Endpunkt auf'
    When call deploy "server"
    The output should include "gemockte Antwort"
  End
End

Describe 'Dateioperationen'
  # Mocken durch Überschreiben der Funktion
  Mock rm
    echo "rm aufgerufen mit: $*"
  End

  It 'versucht Datei zu löschen'
    When call cleanup_temp
    The output should include "rm aufgerufen mit"
  End
End

Spec Helper

# spec/spec_helper.sh

# Gemeinsame Funktionen laden
spec_helper_precheck() {
  minimum_version "0.28.0"
}

spec_helper_loaded() {
  # Testumgebung einrichten
  export TEST_MODE=true
}

spec_helper_configure() {
  # Projektfunktionen importieren
  import 'lib/functions.sh'
}

Testmuster

Exit-Codes testen

# shunit2
test_success_exit() {
    run_command "gültige_eingabe"
    assertEquals 0 $?
}

test_error_exit() {
    run_command "ungültige_eingabe"
    assertEquals 1 $?
}

# shellspec
It 'beendet mit 0 bei Erfolg'
  When call run_command "gültige_eingabe"
  The status should eq 0
End

stdout und stderr testen

# shunit2
test_stdout() {
    result=$(my_function 2>/dev/null)
    assertEquals "erwartete Ausgabe" "$result"
}

test_stderr() {
    error=$(my_function 2>&1 >/dev/null)
    assertContains "$error" "Fehlermeldung"
}

# shellspec
It 'gibt auf stdout aus'
  When call my_function
  The stdout should eq "erwartete Ausgabe"
End

It 'gibt Fehler auf stderr aus'
  When call my_function
  The stderr should include "Fehlermeldung"
End

Mit Fixtures testen

# Test-Fixtures einrichten
setUp() {
    TEST_DIR=$(mktemp -d)
    cat > "$TEST_DIR/config.json" <<EOF
{
    "key": "value"
}
EOF
}

tearDown() {
    rm -rf "$TEST_DIR"
}

test_config_parsing() {
    result=$(parse_config "$TEST_DIR/config.json")
    assertEquals "value" "$result"
}

Interaktive Funktionen testen

# Eingabe über heredoc bereitstellen
test_interactive() {
    result=$(my_prompt <<EOF
ja
EOF
)
    assertEquals "bestätigt" "$result"
}

# Oder printf verwenden
test_with_input() {
    result=$(printf 'yes\n' | my_prompt)
    assertEquals "bestätigt" "$result"
}

Tests ausführen

# shunit2
./test_script.sh

# shellspec
shellspec                    # Alle Specs ausführen
shellspec spec/file_spec.sh  # Bestimmte Spec ausführen
shellspec --format tap       # TAP-Ausgabe
shellspec --jobs 4           # Parallele Ausführung

Best Practices

  1. Eine Assertion pro Test wenn praktikabel
  2. Aussagekräftige Testnamen die erklären, was getestet wird
  3. Tests isolieren – keine Abhängigkeiten zwischen Tests
  4. Grenzfälle testen – leere Eingabe, Sonderzeichen, große Datenmengen
  5. Ressourcen bereinigen in tearDown
  6. Externe Befehle mocken – nicht curl testen, sondern die eigene Logik
  7. Exit-Codes testen nicht nur die Ausgabe

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

Jamie-BitFlight/agentskill-kaizen-meta-docs

Agentskill kaizen plugin documentation index. Load when needing to read about cross-platform notes, improvement plans, or DuckDB integration.

Jamie-BitFlight/bash-51-features

Bash 5.1 release features and improvements with practical examples. Use when working with Bash 5.1 features, epoch time variables, redirection enhancements, or when user asks about Bash 5.1 changes, new features, or version-specific capabilities.

Jamie-BitFlight/bash-52-features

Bash 5.2 release features and improvements with practical examples. Use when working with Bash 5.2 features, variable handling enhancements, readline improvements, or when user asks about Bash 5.2 changes, new features, or version-specific capabilities.

Jamie-BitFlight/bash-53-features

Bash 5.3 release features and improvements with practical examples. Use when working with Bash 5.3 features, new command substitution, GLOBSORT, loadable builtins, or when user asks about Bash 5.3 changes, new features, or version-specific capabilities.

Jamie-BitFlight/bash-development

This skill should be used when the user asks to "write a bash script", "create a shell script", "implement bash function", "parse arguments in bash", "handle errors in bash", or mentions bash development, shell scripting, script templates, or modern bash patterns.

Jamie-BitFlight/bash-lint

This skill should be used when the user asks to "lint bash script", "run shellcheck", "format shell script", "use shfmt", "fix shellcheck errors", or mentions shell script linting, formatting, code quality, or pre-commit hooks for bash.

Jamie-BitFlight/bash-logging

This skill should be used when the user asks to "add logging to bash script", "colorize output", "implement log levels", "CI/CD sections", "terminal colors in bash", or mentions logging functions, emoji output, collapsible CI sections, or shlocksmith.

Jamie-BitFlight/bash-portability

This skill should be used when the user asks about "POSIX compatibility", "portable shell scripts", "cross-shell compatibility", "bashisms", "shebang selection", or mentions writing scripts that work on different shells (bash, sh, dash, zsh) or different systems.

Jamie-BitFlight/brainstorming-skill

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or when users request help with ideation, marketing, and strategic planning. Explores user intent, requirements, and design before implementation using research-validated prompt patterns.

Jamie-BitFlight/clang-format

Configure clang-format code formatting. Use when: user mentions clang-format or .clang-format, analyzing code style/patterns, creating/modifying formatting config, troubleshooting formatting, brace styles/indentation/spacing/alignment/pointer alignment, or codifying conventions.

Jamie-BitFlight/commitlint

When setting up commit message validation for a project. When project has commitlint.config.js or .commitlintrc files. When configuring CI/CD to enforce commit format. When extracting commit rules for LLM prompt generation. When debugging commit message rejection errors.

Jamie-BitFlight/conventional-commits

When writing a git commit message. When task completes and changes need committing. When project uses semantic-release, commitizen, git-cliff. When choosing between feat/fix/chore/docs types. When indicating breaking changes. When generating changelogs from commit history.

Jamie-BitFlight/dasel-reference

Use when querying, modifying, or converting JSON, YAML, TOML, XML, CSV, HCL, or INI with dasel v3. Complete reference for selectors, functions, conditionals, variables, spread operator, type casting, and format-specific patterns.

Jamie-BitFlight/data-exploration

Use when exploring unknown structured data files with dasel v3 — discover schema, list keys, find nested values, sample arrays, identify data types across JSON, YAML, TOML, XML, CSV, HCL, INI formats

Jamie-BitFlight/data-transformation

Use when modifying, converting, or transforming structured data with dasel v3 — in-place mutations, format conversion, batch operations, array manipulation, object construction, and merge patterns across JSON, YAML, TOML, XML, CSV, HCL, INI

Jamie-BitFlight/delegate

Decompose substantive work into phases, dispatch each phase to a sub-agent, and adjudicate what comes back. Use whenever a request asks for implementation, investigation, a fix, a review, or any change to files — including small ones — and whenever you are about to read source or run a diagnostic yourself instead of handing it off. Also use when a report from a sub-agent needs judging, when a phase needs re-dispatching, or when a user names one instance of a pattern. Does not apply when your own prompt begins "Your ROLE_TYPE is sub-agent." — then follow references/sub-agent-contract.md instead.

Jamie-BitFlight/enterprise-hibernate-hbm

Dasel v3 query patterns for Hibernate .hbm.xml mapping files — entity-table binding, Java property-to-column extraction, one-to-many set/list/bag relationship tracing, many-to-one foreign key discovery, batch scanning across 60+ HBM files. Use when querying Hibernate ORM class mappings, extracting schema metadata from Java persistence layer, or auditing entity-column relationships in enterprise legacy codebases.

Jamie-BitFlight/enterprise-installanywhere

Dasel v3 query patterns for InstallAnywhere .iap_xml installer definitions — use when querying action sequences, discovering variables, resolving platform conditions, navigating panels, or comparing installer variants. Files are 2.5+ MB, 65,000+ lines — too large for context reads, requires structural dasel queries.

Jamie-BitFlight/enterprise-maven-pom

Dasel v3 selector patterns for Maven POM XML files — use when querying dependency versions, filtering by groupId or scope, extracting module hierarchy from parent POMs, or detecting version conflicts across enterprise multi-module Java projects. Load this skill when working with pom.xml files using dasel.

Jamie-BitFlight/enterprise-spring-xml

Dasel v3 selectors for Spring bean factory XML — use when querying any Spring ApplicationContext XML for bean discovery, dependency wiring, JMS destination mapping, property injection extraction, or cross-bean reference tracing. Load this skill before writing dasel selectors against Spring bean XML files (applicationContext.xml, *_beans.xml, spring-*.xml).

Verwandte Skills