Master Bash Automated Testing System for comprehensive shell

Bats testing patterns

by wshobson · MIT license · ★ 39,857 on GitHub · updated Sep 21

Bats testing patterns cover

Master Bash Automated Testing System (Bats) for comprehensive shell script testing. Use when writing tests for shell scripts, CI/CD pipelines, or requiring test-driven development of shell utilities.

---
name: bats-testing-patterns
description: Master Bash Automated Testing System (Bats) for comprehensive shell script testing. Use when writing tests for shell scripts, CI/CD pipelines, or requiring test-driven development of shell utilities.
---

# Bats Testing Patterns

Comprehensive guidance for writing comprehensive unit tests for shell scripts using Bats (Bash Automated Testing System), including test patterns, fixtures, and best practices for production-grade shell testing.

## When to Use This Skill

- Writing unit tests for shell scripts
- Implementing test-driven development (TDD) for scripts
- Setting up automated testing in CI/CD pipelines
- Testing edge cases and error conditions
- Validating behavior across different shell environments
- Building maintainable test suites for scripts
- Creating fixtures for complex test scenarios

Overview

Comprehensive guidance for writing comprehensive unit tests for shell scripts using Bats (Bash Automated Testing System), including test patterns, fixtures, and best practices for production-grade shell testing.

Manual install (npx, ZIP)
Claude Codenpx skills add wshobson/agents --skill bats-testing-patterns -g -a claude-code
Claude Code (manual)mkdir -p ~/.claude/skills && curl -sL https://codeload.github.com/wshobson/agents/tar.gz/4236bb91f839 \ | tar -xz -C ~/.claude/skills --strip-components=4 agents-4236bb91f839/plugins/shell-scripting/skills/bats-testing-patterns
Windows (PowerShell)New-Item -ItemType Directory -Force "$HOME\.claude\skills" | Out-Null; Invoke-WebRequest "https://m.agentalley.io/zip/659d2de953b6e9ef45b8/bats-testing-patterns.zip" -OutFile "$env:TEMP\bats-testing-patterns.zip"; Expand-Archive "$env:TEMP\bats-testing-patterns.zip" -DestinationPath "$HOME\.claude\skills" -Force
Claude.ai / desktopDownload the ZIP and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md5.1 KB
  • references/1 file · 7.1 KB
Read the files here
wshobson/4236bb92 files
SKILL.md
Show the full text230 lines

Bats Testing Patterns

Comprehensive guidance for writing comprehensive unit tests for shell scripts using Bats (Bash Automated Testing System), including test patterns, fixtures, and best practices for production-grade shell testing.

When to Use This Skill

  • Writing unit tests for shell scripts
  • Implementing test-driven development (TDD) for scripts
  • Setting up automated testing in CI/CD pipelines
  • Testing edge cases and error conditions
  • Validating behavior across different shell environments
  • Building maintainable test suites for scripts
  • Creating fixtures for complex test scenarios
  • Testing multiple shell dialects (bash, sh, dash)

Detailed patterns and worked examples

Detailed pattern documentation lives in references/details.md. Read that file when the navigation tier above is insufficient.

Testing Error Conditions

#!/usr/bin/env bats

@test "Function fails with missing file" {
    run my_function "/nonexistent/file.txt"
    [ "$status" -ne 0 ]
    [[ "$output" == *"not found"* ]]
}

@test "Function fails with invalid input" {
    run my_function ""
    [ "$status" -ne 0 ]
}

@test "Function fails with permission denied" {
    touch "$TMPDIR/readonly.txt"
    chmod 000 "$TMPDIR/readonly.txt"
    run my_function "$TMPDIR/readonly.txt"
    [ "$status" -ne 0 ]
    chmod 644 "$TMPDIR/readonly.txt"  # Cleanup
}

@test "Function provides helpful error message" {
    run my_function --invalid-option
    [ "$status" -ne 0 ]
    [[ "$output" == *"Usage:"* ]]
}
Testing with Dependencies
#!/usr/bin/env bats

setup() {
    # Check for required tools
    if ! command -v jq &>/dev/null; then
        skip "jq is not installed"
    fi

    export SCRIPT="${BATS_TEST_DIRNAME}/../bin/script.sh"
}

@test "JSON parsing works" {
    skip_if ! command -v jq &>/dev/null
    run my_json_parser '{"key": "value"}'
    [ "$status" -eq 0 ]
}
Testing Shell Compatibility
#!/usr/bin/env bats

@test "Script works in bash" {
    bash "${BATS_TEST_DIRNAME}/../bin/script.sh" arg1
}

@test "Script works in sh (POSIX)" {
    sh "${BATS_TEST_DIRNAME}/../bin/script.sh" arg1
}

@test "Script works in dash" {
    if command -v dash &>/dev/null; then
        dash "${BATS_TEST_DIRNAME}/../bin/script.sh" arg1
    else
        skip "dash not installed"
    fi
}
Parallel Execution
#!/usr/bin/env bats

@test "Multiple independent operations" {
    run bash -c 'for i in {1..10}; do
        my_operation "$i" &
    done
    wait'
    [ "$status" -eq 0 ]
}

@test "Concurrent file operations" {
    for i in {1..5}; do
        my_function "$TMPDIR/file$i" &
    done
    wait
    [ -f "$TMPDIR/file1" ]
    [ -f "$TMPDIR/file5" ]
}

Test Helper Pattern

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

# Source script under test
export SCRIPT_DIR="${BATS_TEST_DIRNAME%/*}/bin"

# Common test utilities
assert_file_exists() {
    if [ ! -f "$1" ]; then
        echo "Expected file to exist: $1"
        return 1
    fi
}

assert_file_equals() {
    local file="$1"
    local expected="$2"

    if [ ! -f "$file" ]; then
        echo "File does not exist: $file"
        return 1
    fi

    local actual=$(cat "$file")
    if [ "$actual" != "$expected" ]; then
        echo "File contents do not match"
        echo "Expected: $expected"
        echo "Actual: $actual"
        return 1
    fi
}

# Create temporary test directory
setup_test_dir() {
    export TEST_DIR=$(mktemp -d)
}

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

Integration with CI/CD

GitHub Actions Workflow
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Install Bats
        run: |
          npm install --global bats

      - name: Run Tests
        run: |
          bats tests/*.bats

      - name: Run Tests with Tap Reporter
        run: |
          bats tests/*.bats --tap | tee test_output.tap
Makefile Integration
.PHONY: test test-verbose test-tap

test:
	bats tests/*.bats

test-verbose:
	bats tests/*.bats --verbose

test-tap:
	bats tests/*.bats --tap

test-parallel:
	bats tests/*.bats --parallel 4

coverage: test
	# Optional: Generate coverage reports

Best Practices

  1. Test one thing per test - Single responsibility principle
  2. Use descriptive test names - Clearly states what is being tested
  3. Clean up after tests - Always remove temporary files in teardown
  4. Test both success and failure paths - Don't just test happy path
  5. Mock external dependencies - Isolate unit under test
  6. Use fixtures for complex data - Makes tests more readable
  7. Run tests in CI/CD - Catch regressions early
  8. Test across shell dialects - Ensure portability
  9. Keep tests fast - Run in parallel when possible
  10. Document complex test setup - Explain unusual patterns
1---
2name: bats-testing-patterns
3description: Master Bash Automated Testing System (Bats) for comprehensive shell script testing. Use when writing tests for shell scripts, CI/CD pipelines, or requiring test-driven development of shell utilities.
4---
5 
6# Bats Testing Patterns
7 
8Comprehensive guidance for writing comprehensive unit tests for shell scripts using Bats (Bash Automated Testing System), including test patterns, fixtures, and best practices for production-grade shell testing.
9 
10## When to Use This Skill
11 
12- Writing unit tests for shell scripts
13- Implementing test-driven development (TDD) for scripts
14- Setting up automated testing in CI/CD pipelines
15- Testing edge cases and error conditions
16- Validating behavior across different shell environments
17- Building maintainable test suites for scripts
18- Creating fixtures for complex test scenarios
19- Testing multiple shell dialects (bash, sh, dash)
20 
21## Detailed patterns and worked examples
22 
23Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient.
24 
25## Testing Error Conditions
26 
27```bash
28#!/usr/bin/env bats
29 
30@test "Function fails with missing file" {
31 run my_function "/nonexistent/file.txt"
32 [ "$status" -ne 0 ]
33 [[ "$output" == *"not found"* ]]
34}
35 
36@test "Function fails with invalid input" {
37 run my_function ""
38 [ "$status" -ne 0 ]
39}
40 
41@test "Function fails with permission denied" {
42 touch "$TMPDIR/readonly.txt"
43 chmod 000 "$TMPDIR/readonly.txt"
44 run my_function "$TMPDIR/readonly.txt"
45 [ "$status" -ne 0 ]
46 chmod 644 "$TMPDIR/readonly.txt" # Cleanup
47}
48 
49@test "Function provides helpful error message" {
50 run my_function --invalid-option
51 [ "$status" -ne 0 ]
52 [[ "$output" == *"Usage:"* ]]
53}
54```
55 
56### Testing with Dependencies
57 
58```bash
59#!/usr/bin/env bats
60 
61setup() {
62 # Check for required tools
63 if ! command -v jq &>/dev/null; then
64 skip "jq is not installed"
65 fi
66 
67 export SCRIPT="${BATS_TEST_DIRNAME}/../bin/script.sh"
68}
69 
70@test "JSON parsing works" {
71 skip_if ! command -v jq &>/dev/null
72 run my_json_parser '{"key": "value"}'
73 [ "$status" -eq 0 ]
74}
75```
76 
77### Testing Shell Compatibility
78 
79```bash
80#!/usr/bin/env bats
81 
82@test "Script works in bash" {
83 bash "${BATS_TEST_DIRNAME}/../bin/script.sh" arg1
84}
85 
86@test "Script works in sh (POSIX)" {
87 sh "${BATS_TEST_DIRNAME}/../bin/script.sh" arg1
88}
89 
90@test "Script works in dash" {
91 if command -v dash &>/dev/null; then
92 dash "${BATS_TEST_DIRNAME}/../bin/script.sh" arg1
93 else
94 skip "dash not installed"
95 fi
96}
97```
98 
99### Parallel Execution
100 
101```bash
102#!/usr/bin/env bats
103 
104@test "Multiple independent operations" {
105 run bash -c 'for i in {1..10}; do
106 my_operation "$i" &
107 done
108 wait'
109 [ "$status" -eq 0 ]
110}
111 
112@test "Concurrent file operations" {
113 for i in {1..5}; do
114 my_function "$TMPDIR/file$i" &
115 done
116 wait
117 [ -f "$TMPDIR/file1" ]
118 [ -f "$TMPDIR/file5" ]
119}
120```
121 
122## Test Helper Pattern
123 
124### test_helper.sh
125 
126```bash
127#!/usr/bin/env bash
128 
129# Source script under test
130export SCRIPT_DIR="${BATS_TEST_DIRNAME%/*}/bin"
131 
132# Common test utilities
133assert_file_exists() {
134 if [ ! -f "$1" ]; then
135 echo "Expected file to exist: $1"
136 return 1
137 fi
138}
139 
140assert_file_equals() {
141 local file="$1"
142 local expected="$2"
143 
144 if [ ! -f "$file" ]; then
145 echo "File does not exist: $file"
146 return 1
147 fi
148 
149 local actual=$(cat "$file")
150 if [ "$actual" != "$expected" ]; then
151 echo "File contents do not match"
152 echo "Expected: $expected"
153 echo "Actual: $actual"
154 return 1
155 fi
156}
157 
158# Create temporary test directory
159setup_test_dir() {
160 export TEST_DIR=$(mktemp -d)
161}
162 
163cleanup_test_dir() {
164 rm -rf "$TEST_DIR"
165}
166```
167 
168## Integration with CI/CD
169 
170### GitHub Actions Workflow
171 
172```yaml
173name: Tests
174 
175on: [push, pull_request]
176 
177jobs:
178 test:
179 runs-on: ubuntu-latest
180 
181 steps:
182 - uses: actions/checkout@v3
183 
184 - name: Install Bats
185 run: |
186 npm install --global bats
187 
188 - name: Run Tests
189 run: |
190 bats tests/*.bats
191 
192 - name: Run Tests with Tap Reporter
193 run: |
194 bats tests/*.bats --tap | tee test_output.tap
195```
196 
197### Makefile Integration
198 
199```makefile
200.PHONY: test test-verbose test-tap
201 
202test:
203 bats tests/*.bats
204 
205test-verbose:
206 bats tests/*.bats --verbose
207 
208test-tap:
209 bats tests/*.bats --tap
210 
211test-parallel:
212 bats tests/*.bats --parallel 4
213 
214coverage: test
215 # Optional: Generate coverage reports
216```
217 
218## Best Practices
219 
2201. **Test one thing per test** - Single responsibility principle
2212. **Use descriptive test names** - Clearly states what is being tested
2223. **Clean up after tests** - Always remove temporary files in teardown
2234. **Test both success and failure paths** - Don't just test happy path
2245. **Mock external dependencies** - Isolate unit under test
2256. **Use fixtures for complex data** - Makes tests more readable
2267. **Run tests in CI/CD** - Catch regressions early
2278. **Test across shell dialects** - Ensure portability
2289. **Keep tests fast** - Run in parallel when possible
22910. **Document complex test setup** - Explain unusual patterns
230 
View all files on GitHub →

Details

Updated
Sep 21, 2026
License
MIT
Stars on the repo
★ 39,857
Checked
Source
wshobson/agents ↗
Creator
wshobson · 179 listings
View creator

Similar skills

See all →
Skill29 production-ready scripts for iOS app testing, buildingIos simulator skillconorluddy/ios-simulator-skill · by conorluddy29 production-ready scripts for iOS app testing, building, and automation. Provides semantic UI navigation, build automation, accessibility testing, and simulator lifecycle management. Optimized for AI agents with minimal token output.★ 1.3k GitHub starsSkillMoAI unified orchestrator for autonomous developmentmodu-ai/moai-adk · by modu-aiMoAI unified orchestrator for autonomous development. Routes natural language or subcommands (plan, run, sync, project, fix, loop, mx, feedback, review, clean, codemaps, gate, e2e, harness, goal, gtd, todo) to specialized agents.★ 1.2k GitHub starsSkillWrite Android unit, Compose UI, and Hilt-integrated testsAndroid Testing StandardsHoangNguyen0403/agent-skills-standard · by HoangNguyen0403Write Android unit, Compose UI, and Hilt-integrated tests. Use when designing test behavior with MockK or coroutine test utilities; defer database/WorkManager-specific recipes to the owning feature skill.★ 569 GitHub starsSkillImplementing any feature or bugfixTest-Driven Development (TDD)obra/superpowers · by obraUse when implementing any feature or bugfix, before writing implementation code★ 290k GitHub starsSkillToolkit for interacting with and testing local webWebapp testinganthropics/skills · by anthropicsToolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.★ 178k GitHub starsPromptGuide to fixing bugs using a test-first approachTest first bug fixing approachf/prompts.chat · by Ilker UlusoyGuide to fixing bugs using a test-first approach, ensuring code reliability through systematic testing and implementation.New listing

More from wshobson

SkillMaster C/.NET backend development patterns for buildingwshobson/agents · by wshobsonMaster C#/.NET backend development patterns for building robust APIs, MCP servers, and enterprise applications. Covers async/await, dependency injection, Entity Framework Core, Dapper, configuration, caching, and testing with xUnit. Use when developing .NET backends, reviewing C# code, or designing API architectures.★ 39.9k GitHub starsSkillImplement WCAG 2.2 compliant interfaces with mobileAccessibility compliancewshobson/agents · by wshobsonImplement WCAG 2.2 compliant interfaces with mobile accessibility, inclusive design patterns, and assistive technology support. Use when auditing accessibility, implementing ARIA patterns, building for screen readers, or ensuring inclusive user experiences.★ 39.9k GitHub starsSkillMaster Material Design 3 and Jetpack Compose patternsAndroid Mobile Designwshobson/agents · by wshobsonMaster Material Design 3 and Jetpack Compose patterns for building native Android apps. Use when designing Android interfaces, implementing Compose UI, or following Google's Material Design guidelines.★ 39.9k GitHub starsSkillMigrate from AngularJS to Angular using hybrid modeAngular migrationwshobson/agents · by wshobsonMigrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.★ 39.9k GitHub starsSkillUnderstand anti-reversing, obfuscationAnti reversing techniqueswshobson/agents · by wshobsonUnderstand anti-reversing, obfuscation, and protection techniques encountered during software analysis. Use this skill when analyzing malware evasion techniques, when implementing anti-debugging protections for CTF challenges, when reverse engineering packed binaries, or when building security research tools that need to detect virtualized environments.★ 39.9k GitHub starsSkillBuild production Apache Airflow DAGs with best practicesApache Airflow DAG Patternswshobson/agents · by wshobsonBuild production Apache Airflow DAGs with best practices for operators, sensors, testing, and deployment. Use when creating data pipelines, orchestrating workflows, or scheduling batch jobs.★ 39.9k GitHub stars