Token导航 LogoToken导航TokenDH.com
开发执行命令github未标认证来源可访问clear审计通过

shell-testing-frameworkshell 测试框架

Agent Skill

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

总安装

190

周安装

8

GitHub Stars

1

下载量

67
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:shell-testing-framework(shell 测试框架)
来源仓库:https://github.com/manutej/crush-mcp-server
仓库路径:skills/shell-testing-framework
安装命令:
npx skills add https://github.com/manutej/crush-mcp-server --skill shell-testing-framework
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/manutej/crush-mcp-server --skill shell-testing-framework

简介

用于辅助测试设计、自动化测试和回归验证,适合编写测试用例或分析失败日志。

  • 适用于 Shell 脚本测试、命令行工具验证或 CI/CD 流程支持场景。
  • 通过 npx skills add 命令从指定 GitHub 仓库安装并使用。
  • 使用时需确认项目测试框架和运行命令,避免为了通过测试而改坏逻辑。
  • 涉及外部服务时应区分本地模拟与真实环境。

SKILL.md

Shell Testing Framework Expert

Comprehensive testing expertise for bash shell scripts using patterns and methodologies from the unix-goto project, emphasizing 100% test coverage, systematic test organization, and performance validation.

When to Use This Skill

Use this skill when:

  • Writing test suites for bash shell scripts
  • Implementing 100% test coverage requirements
  • Organizing tests into unit, integration, edge case, and performance categories
  • Creating assertion patterns for shell script validation
  • Setting up test infrastructure and helpers
  • Writing performance tests for shell functions
  • Generating test reports and summaries
  • Debugging test failures
  • Validating shell script behavior

Do NOT use this skill for:

  • Testing non-shell applications (use language-specific frameworks)
  • Simple ad-hoc script validation
  • Production testing (use for development/CI only)
  • General QA testing (this is developer-focused unit testing)

Core Testing Philosophy

The 100% Coverage Rule

Every core feature in unix-goto has 100% test coverage. This is NON-NEGOTIABLE.

Coverage Requirements:

  • Core navigation: 100%
  • Cache system: 100%
  • Bookmarks: 100%
  • History: 100%
  • Benchmarks: 100%
  • New features: 100%

What This Means:

  • Every function has tests
  • Every code path is exercised
  • Every error condition is validated
  • Every edge case is covered
  • Every performance target is verified

Test-Driven Development Approach

Workflow:

  1. Write tests FIRST (based on feature spec)
  2. Watch tests FAIL (red)
  3. Implement feature
  4. Watch tests PASS (green)
  5. Refactor if needed
  6. Validate all tests still pass

Core Knowledge

Standard Test File Structure

Every test file follows this exact structure:

#!/bin/bash
# Test suite for [feature] functionality

set -e  # Exit on error

# ============================================
# Setup
# ============================================

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/lib/module.sh"

# ============================================
# Test Counters
# ============================================

TESTS_PASSED=0
TESTS_FAILED=0

# ============================================
# Test Helpers
# ============================================

pass() {
    echo "✓ PASS: $1"
    ((TESTS_PASSED++))
}

fail() {
    echo "✗ FAIL: $1"
    ((TESTS_FAILED++))
}

# ============================================
# Test Functions
# ============================================

# Test 1: [Category] - [Description]
test_feature_basic() {
    # Arrange
    local input="test"
    local expected="expected_output"

    # Act
    local result=$(function_under_test "$input")

    # Assert
    if [[ "$result" == "$expected" ]]; then
        pass "Basic feature test"
    else
        fail "Basic feature test: expected '$expected', got '$result'"
    fi
}

# ============================================
# Test Execution
# ============================================

# Run all tests
test_feature_basic

# ============================================
# Summary
# ============================================

echo ""
echo "═══════════════════════════════════════"
echo "Tests passed: $TESTS_PASSED"
echo "Tests failed: $TESTS_FAILED"
echo "═══════════════════════════════════════"

# Exit with proper code
[ $TESTS_FAILED -eq 0 ] && exit 0 || exit 1

The Arrange-Act-Assert Pattern

EVERY test function MUST follow this three-phase structure:

1. Arrange - Set up test conditions

# Arrange
local input="test-value"
local expected="expected-result"
local temp_file=$(mktemp)
echo "test data" > "$temp_file"

2. Act - Execute the code under test

# Act
local result=$(function_under_test "$input")
local exit_code=$?

3. Assert - Verify the results

# Assert
if [[ "$result" == "$expected" && $exit_code -eq 0 ]]; then
    pass "Test description"
else
    fail "Test failed: expected '$expected', got '$result'"
fi

Complete Example:

test_cache_lookup_single_match() {
    # Arrange - Create cache with single match
    local cache_file="$HOME/.goto_index"
    cat > "$cache_file" << EOF
# unix-goto folder index cache
#---
unix-goto|/Users/manu/Git_Repos/unix-goto|2|1234567890
EOF

    # Act - Lookup folder
    local result=$(__goto_cache_lookup "unix-goto")
    local exit_code=$?

    # Assert - Should return exact path
    local expected="/Users/manu/Git_Repos/unix-goto"
    if [[ "$result" == "$expected" && $exit_code -eq 0 ]]; then
        pass "Cache lookup returns single match"
    else
        fail "Expected '$expected' with code 0, got '$result' with code $exit_code"
    fi
}

The Four Test Categories

EVERY feature requires tests in ALL four categories:

Category 1: Unit Tests

Purpose: Test individual functions in isolation

Characteristics:

  • Single function under test
  • Minimal dependencies
  • Fast execution (<1ms per test)
  • Clear, focused assertions

Example - Cache Lookup Unit Test:

test_cache_lookup_not_found() {
    # Arrange
    local cache_file="$HOME/.goto_index"
    cat > "$cache_file" << EOF
# unix-goto folder index cache
#---
unix-goto|/Users/manu/Git_Repos/unix-goto|2|1234567890
EOF

    # Act
    local result=$(__goto_cache_lookup "nonexistent")
    local exit_code=$?

    # Assert
    if [[ -z "$result" && $exit_code -eq 1 ]]; then
        pass "Cache lookup not found returns code 1"
    else
        fail "Expected empty result with code 1, got '$result' with code $exit_code"
    fi
}

test_cache_lookup_multiple_matches() {
    # Arrange
    local cache_file="$HOME/.goto_index"
    cat > "$cache_file" << EOF
# unix-goto folder index cache
#---
project|/Users/manu/project1|2|1234567890
project|/Users/manu/project2|2|1234567891
EOF

    # Act
    local result=$(__goto_cache_lookup "project")
    local exit_code=$?

    # Assert - Should return all matches with code 2
    local line_count=$(echo "$result" | wc -l)
    if [[ $line_count -eq 2 && $exit_code -eq 2 ]]; then
        pass "Cache lookup returns multiple matches with code 2"
    else
        fail "Expected 2 lines with code 2, got $line_count lines with code $exit_code"
    fi
}

Unit Test Checklist:

  • Test with valid input
  • Test with invalid input
  • Test with empty input
  • Test with boundary values
  • Test return codes
  • Test output format

Category 2: Integration Tests

Purpose: Test how multiple modules work together

Characteristics:

  • Multiple functions/modules interact
  • Test realistic workflows
  • Validate end-to-end behavior
  • Moderate execution time (<100ms per test)

Example - Navigation Integration Test:

test_navigation_with_cache() {
    # Arrange - Setup complete navigation environment
    local cache_file="$HOME/.goto_index"
    local history_file="$HOME/.goto_history"

    cat > "$cache_file" << EOF
# unix-goto folder index cache
#---
unix-goto|/Users/manu/Git_Repos/unix-goto|2|1234567890
EOF

    # Act - Perform full navigation
    local start_dir=$(pwd)
    goto unix-goto
    local nav_exit_code=$?
    local end_dir=$(pwd)

    # Assert - Should navigate and track history
    local expected_dir="/Users/manu/Git_Repos/unix-goto"
    local history_recorded=false

    if grep -q "$expected_dir" "$history_file" 2>/dev/null; then
        history_recorded=true
    fi

    if [[ "$end_dir" == "$expected_dir" && $nav_exit_code -eq 0 && $history_recorded == true ]]; then
        pass "Navigation with cache and history tracking"
    else
        fail "Integration test failed: nav=$nav_exit_code, dir=$end_dir, history=$history_recorded"
    fi

    # Cleanup
    cd "$start_dir"
}

test_bookmark_creation_and_navigation() {
    # Arrange
    local bookmark_file="$HOME/.goto_bookmarks"
    rm -f "$bookmark_file"

    # Act - Create bookmark and navigate
    bookmark add testwork /Users/manu/work
    local add_code=$?

    goto @testwork
    local nav_code=$?
    local nav_dir=$(pwd)

    # Assert
    local expected_dir="/Users/manu/work"
    if [[ $add_code -eq 0 && $nav_code -eq 0 && "$nav_dir" == "$expected_dir" ]]; then
        pass "Bookmark creation and navigation integration"
    else
        fail "Integration failed: add=$add_code, nav=$nav_code, dir=$nav_dir"
    fi
}

Integration Test Checklist:

  • Test common user workflows
  • Test module interactions
  • Test data persistence
  • Test state changes
  • Test error propagation
  • Test cleanup behavior

Category 3: Edge Cases

Purpose: Test boundary conditions and unusual scenarios

Characteristics:

  • Unusual but valid inputs
  • Boundary conditions
  • Error scenarios
  • Race conditions
  • Resource limits

Example - Edge Case Tests:

test_empty_cache_file() {
    # Arrange - Create empty cache file
    local cache_file="$HOME/.goto_index"
    touch "$cache_file"

    # Act
    local result=$(__goto_cache_lookup "anything")
    local exit_code=$?

    # Assert - Should handle gracefully
    if [[ -z "$result" && $exit_code -eq 1 ]]; then
        pass "Empty cache file handled gracefully"
    else
        fail "Empty cache should return code 1"
    fi
}

test_malformed_cache_entry() {
    # Arrange - Cache with malformed entry
    local cache_file="$HOME/.goto_index"
    cat > "$cache_file" << EOF
# unix-goto folder index cache
#---
unix-goto|/path|missing|fields
valid-entry|/valid/path|2|1234567890
EOF

    # Act
    local result=$(__goto_cache_lookup "valid-entry")
    local exit_code=$?

    # Assert - Should still find valid entry
    if [[ "$result" == "/valid/path" && $exit_code -eq 0 ]]; then
        pass "Malformed entry doesn't break valid lookups"
    else
        fail "Should handle malformed entries gracefully"
    fi
}

test_very_long_path() {
    # Arrange - Create entry with very long path
    local long_path=$(printf '/very/long/path/%.0s' {1..50})
    local cache_file="$HOME/.goto_index"
    cat > "$cache_file" << EOF
# unix-goto folder index cache
#---
longpath|${long_path}|50|1234567890
EOF

    # Act
    local result=$(__goto_cache_lookup "longpath")
    local exit_code=$?

    # Assert - Should handle long paths
    if [[ "$result" == "$long_path" && $exit_code -eq 0 ]]; then
        pass "Very long paths handled correctly"
    else
        fail "Long path handling failed"
    fi
}

test_special_characters_in_folder_name() {
    # Arrange - Folder with special characters
    local cache_file="$HOME/.goto_index"
    cat > "$cache_file" << EOF
# unix-goto folder index cache
#---
my-project_v2.0|/Users/manu/my-project_v2.0|2|1234567890
EOF

    # Act
    local result=$(__goto_cache_lookup "my-project_v2.0")
    local exit_code=$?

    # Assert
    if [[ "$result" == "/Users/manu/my-project_v2.0" && $exit_code -eq 0 ]]; then
        pass "Special characters in folder name"
    else
        fail "Special character handling failed"
    fi
}

test_concurrent_cache_access() {
    # Arrange
    local cache_file="$HOME/.goto_index"
    __goto_cache_build

    # Act - Simulate concurrent access
    (
        for i in {1..10}; do
            __goto_cache_lookup "unix-goto" &
        done
        wait
    )
    local exit_code=$?

    # Assert - Should handle concurrent reads
    if [[ $exit_code -eq 0 ]]; then
        pass "Concurrent cache access handled"
    else
        fail "Concurrent access failed"
    fi
}

Edge Case Test Checklist:

  • Empty inputs
  • Missing files
  • Malformed data
  • Very large inputs
  • Special characters
  • Concurrent access
  • Resource exhaustion
  • Permission errors

Category 4: Performance Tests

Purpose: Validate performance targets are met

Characteristics:

  • Measure execution time
  • Compare against targets
  • Use statistical analysis
  • Test at scale

Example - Performance Tests:

test_cache_lookup_speed() {
    # Arrange - Build cache
    __goto_cache_build

    # Act - Measure lookup time
    local start=$(date +%s%N)
    __goto_cache_lookup "unix-goto"
    local end=$(date +%s%N)

    # Assert - Should be <100ms
    local duration=$(((end - start) / 1000000))
    local target=100

    if [ $duration -lt $target ]; then
        pass "Cache lookup speed: ${duration}ms (target: <${target}ms)"
    else
        fail "Cache too slow: ${duration}ms (target: <${target}ms)"
    fi
}

test_cache_build_performance() {
    # Arrange - Clean cache
    rm -f ~/.goto_index

    # Act - Measure build time
    local start=$(date +%s%N)
    __goto_cache_build
    local end=$(date +%s%N)

    # Assert - Should be <5 seconds
    local duration=$(((end - start) / 1000000))
    local target=5000

    if [ $duration -lt $target ]; then
        pass "Cache build speed: ${duration}ms (target: <${target}ms)"
    else
        fail "Cache build too slow: ${duration}ms (target: <${target}ms)"
    fi
}

test_history_retrieval_speed() {
    # Arrange - Create history with 100 entries
    local history_file="$HOME/.goto_history"
    rm -f "$history_file"
    for i in {1..100}; do
        echo "$(date +%s)|/path/to/dir$i" >> "$history_file"
    done

    # Act - Measure retrieval time
    local start=$(date +%s%N)
    __goto_recent_dirs 10
    local end=$(date +%s%N)

    # Assert - Should be <10ms
    local duration=$(((end - start) / 1000000))
    local target=10

    if [ $duration -lt $target ]; then
        pass "History retrieval: ${duration}ms (target: <${target}ms)"
    else
        fail "History too slow: ${duration}ms (target: <${target}ms)"
    fi
}

test_benchmark_cache_at_scale() {
    # Arrange - Create large workspace
    local workspace=$(mktemp -d)
    for i in {1..500}; do
        mkdir -p "$workspace/folder-$i"
    done

    # Act - Build cache and measure lookup
    local old_paths="$GOTO_SEARCH_PATHS"
    export GOTO_SEARCH_PATHS="$workspace"

    __goto_cache_build

    local start=$(date +%s%N)
    __goto_cache_lookup "folder-250"
    local end=$(date +%s%N)

    # Assert - Even with 500 folders, should be <100ms
    local duration=$(((end - start) / 1000000))
    local target=100

    if [ $duration -lt $target ]; then
        pass "Cache at scale (500 folders): ${duration}ms"
    else
        fail "Cache at scale too slow: ${duration}ms"
    fi

    # Cleanup
    export GOTO_SEARCH_PATHS="$old_paths"
    rm -rf "$workspace"
}

Performance Test Checklist:

  • Measure critical path operations
  • Compare against defined targets
  • Test at realistic scale
  • Test with maximum load
  • Calculate statistics (min/max/mean/median)
  • Verify no performance regressions

Assertion Patterns

Basic Assertions

String Equality:

assert_equal() {
    local expected="$1"
    local actual="$2"
    local message="${3:-String equality}"

    if [[ "$actual" == "$expected" ]]; then
        pass "$message"
    else
        fail "$message: expected '$expected', got '$actual'"
    fi
}

# Usage
assert_equal "expected" "$result" "Function returns expected value"

Exit Code Assertions:

assert_success() {
    local exit_code=$?
    local message="${1:-Command should succeed}"

    if [ $exit_code -eq 0 ]; then
        pass "$message"
    else
        fail "$message: exit code $exit_code"
    fi
}

assert_failure() {
    local exit_code=$?
    local message="${1:-Command should fail}"

    if [ $exit_code -ne 0 ]; then
        pass "$message"
    else
        fail "$message: expected non-zero exit code"
    fi
}

# Usage
some_command
assert_success "Command executed successfully"

Numeric Comparisons:

assert_less_than() {
    local actual=$1
    local limit=$2
    local message="${3:-Value should be less than limit}"

    if [ $actual -lt $limit ]; then
        pass "$message: $actual < $limit"
    else
        fail "$message: $actual >= $limit"
    fi
}

assert_greater_than() {
    local actual=$1
    local limit=$2
    local message="${3:-Value should be greater than limit}"

    if [ $actual -gt $limit ]; then
        pass "$message: $actual > $limit"
    else
        fail "$message: $actual <= $limit"
    fi
}

# Usage
assert_less_than $duration 100 "Cache lookup time"

File System Assertions

File Existence:

assert_file_exists() {
    local file="$1"
    local message="${2:-File should exist}"

    if [ -f "$file" ]; then
        pass "$message: $file"
    else
        fail "$message: $file not found"
    fi
}

assert_dir_exists() {
    local dir="$1"
    local message="${2:-Directory should exist}"

    if [ -d "$dir" ]; then
        pass "$message: $dir"
    else
        fail "$message: $dir not found"
    fi
}

# Usage
assert_file_exists "$HOME/.goto_index" "Cache file created"

File Content Assertions:

assert_file_contains() {
    local file="$1"
    local pattern="$2"
    local message="${3:-File should contain pattern}"

    if grep -q "$pattern" "$file" 2>/dev/null; then
        pass "$message"
    else
        fail "$message: pattern '$pattern' not found in $file"
    fi
}

assert_line_count() {
    local file="$1"
    local expected=$2
    local message="${3:-File should have expected line count}"

    local actual=$(wc -l < "$file" | tr -d ' ')

    if [ $actual -eq $expected ]; then
        pass "$message: $actual lines"
    else
        fail "$message: expected $expected lines, got $actual"
    fi
}

# Usage
assert_file_contains "$HOME/.goto_bookmarks" "work|/path/to/work"
assert_line_count "$HOME/.goto_history" 10

Output Assertions

Contains Pattern:

assert_output_contains() {
    local output="$1"
    local pattern="$2"
    local message="${3:-Output should contain pattern}"

    if [[ "$output" =~ $pattern ]]; then
        pass "$message"
    else
        fail "$message: pattern '$pattern' not found in output"
    fi
}

# Usage
output=$(goto recent)
assert_output_contains "$output" "/Users/manu/work" "Recent shows work directory"

Empty Output:

assert_output_empty() {
    local output="$1"
    local message="${2:-Output should be empty}"

    if [[ -z "$output" ]]; then
        pass "$message"
    else
        fail "$message: got '$output'"
    fi
}

# Usage
output=$(goto nonexistent 2>&1)
assert_output_empty "$output"

Test Helper Functions

Create a reusable test helpers library:

#!/bin/bash
# test-helpers.sh - Reusable test utilities

# ============================================
# Setup/Teardown
# ============================================

setup_test_env() {
    # Create temp directory for test
    TEST_TEMP_DIR=$(mktemp -d)

    # Backup real files
    [ -f "$HOME/.goto_index" ] && cp "$HOME/.goto_index" "$TEST_TEMP_DIR/goto_index.bak"
    [ -f "$HOME/.goto_bookmarks" ] && cp "$HOME/.goto_bookmarks" "$TEST_TEMP_DIR/goto_bookmarks.bak"
    [ -f "$HOME/.goto_history" ] && cp "$HOME/.goto_history" "$TEST_TEMP_DIR/goto_history.bak"
}

teardown_test_env() {
    # Restore backups
    [ -f "$TEST_TEMP_DIR/goto_index.bak" ] && mv "$TEST_TEMP_DIR/goto_index.bak" "$HOME/.goto_index"
    [ -f "$TEST_TEMP_DIR/goto_bookmarks.bak" ] && mv "$TEST_TEMP_DIR/goto_bookmarks.bak" "$HOME/.goto_bookmarks"
    [ -f "$TEST_TEMP_DIR/goto_history.bak" ] && mv "$TEST_TEMP_DIR/goto_history.bak" "$HOME/.goto_history"

    # Remove temp directory
    rm -rf "$TEST_TEMP_DIR"
}

# ============================================
# Test Data Creation
# ============================================

create_test_cache() {
    local entries="${1:-10}"
    local cache_file="$HOME/.goto_index"

    cat > "$cache_file" << EOF
# unix-goto folder index cache
# Version: 1.0
# Built: $(date +%s)
# Depth: 3
# Format: folder_name|full_path|depth|last_modified
#---
EOF

    for i in $(seq 1 $entries); do
        echo "folder-$i|/path/to/folder-$i|2|$(date +%s)" >> "$cache_file"
    done
}

create_test_bookmarks() {
    local count="${1:-5}"
    local bookmark_file="$HOME/.goto_bookmarks"

    rm -f "$bookmark_file"
    for i in $(seq 1 $count); do
        echo "bookmark$i|/path/to/bookmark$i|$(date +%s)" >> "$bookmark_file"
    done
}

create_test_history() {
    local count="${1:-20}"
    local history_file="$HOME/.goto_history"

    rm -f "$history_file"
    for i in $(seq 1 $count); do
        echo "$(date +%s)|/path/to/dir$i" >> "$history_file"
    done
}

# ============================================
# Timing Utilities
# ============================================

time_function_ms() {
    local func="$1"
    shift
    local args="$@"

    local start=$(date +%s%N)
    $func $args
    local end=$(date +%s%N)

    echo $(((end - start) / 1000000))
}

# ============================================
# Assertion Helpers
# ============================================

assert_function_exists() {
    local func="$1"

    if declare -f "$func" > /dev/null; then
        pass "Function $func exists"
    else
        fail "Function $func not found"
    fi
}

assert_variable_set() {
    local var="$1"

    if [ -n "${!var}" ]; then
        pass "Variable $var is set"
    else
        fail "Variable $var not set"
    fi
}

Examples

Example 1: Complete Cache Test Suite

#!/bin/bash
# test-cache.sh - Comprehensive cache system test suite

set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/lib/cache-index.sh"
source "$SCRIPT_DIR/test-helpers.sh"

TESTS_PASSED=0
TESTS_FAILED=0

pass() { echo "✓ PASS: $1"; ((TESTS_PASSED++)); }
fail() { echo "✗ FAIL: $1"; ((TESTS_FAILED++)); }

# ============================================
# Unit Tests
# ============================================

echo "Unit Tests"
echo "─────────────────────────────────────────"

test_cache_lookup_single_match() {
    setup_test_env

    # Arrange
    cat > "$HOME/.goto_index" << EOF
# unix-goto folder index cache
#---
unix-goto|/Users/manu/Git_Repos/unix-goto|2|1234567890
EOF

    # Act
    local result=$(__goto_cache_lookup "unix-goto")
    local exit_code=$?

    # Assert
    if [[ "$result" == "/Users/manu/Git_Repos/unix-goto" && $exit_code -eq 0 ]]; then
        pass "Unit: Single match lookup"
    else
        fail "Unit: Single match lookup - got '$result' code $exit_code"
    fi

    teardown_test_env
}

test_cache_lookup_not_found() {
    setup_test_env

    # Arrange
    create_test_cache 5

    # Act
    local result=$(__goto_cache_lookup "nonexistent")
    local exit_code=$?

    # Assert
    if [[ -z "$result" && $exit_code -eq 1 ]]; then
        pass "Unit: Not found returns code 1"
    else
        fail "Unit: Not found - got '$result' code $exit_code"
    fi

    teardown_test_env
}

test_cache_lookup_multiple_matches() {
    setup_test_env

    # Arrange
    cat > "$HOME/.goto_index" << EOF
# unix-goto folder index cache
#---
project|/Users/manu/project1|2|1234567890
project|/Users/manu/project2|2|1234567891
EOF

    # Act
    local result=$(__goto_cache_lookup "project")
    local exit_code=$?
    local line_count=$(echo "$result" | wc -l | tr -d ' ')

    # Assert
    if [[ $line_count -eq 2 && $exit_code -eq 2 ]]; then
        pass "Unit: Multiple matches returns code 2"
    else
        fail "Unit: Multiple matches - got $line_count lines code $exit_code"
    fi

    teardown_test_env
}

# ============================================
# Integration Tests
# ============================================

echo ""
echo "Integration Tests"
echo "─────────────────────────────────────────"

test_cache_build_and_lookup() {
    setup_test_env

    # Arrange
    rm -f "$HOME/.goto_index"

    # Act
    __goto_cache_build
    local build_code=$?

    local result=$(__goto_cache_lookup "unix-goto")
    local lookup_code=$?

    # Assert
    if [[ $build_code -eq 0 && $lookup_code -eq 0 && -n "$result" ]]; then
        pass "Integration: Build and lookup"
    else
        fail "Integration: Build ($build_code) and lookup ($lookup_code) failed"
    fi

    teardown_test_env
}

# ============================================
# Edge Cases
# ============================================

echo ""
echo "Edge Case Tests"
echo "─────────────────────────────────────────"

test_empty_cache_file() {
    setup_test_env

    # Arrange
    touch "$HOME/.goto_index"

    # Act
    local result=$(__goto_cache_lookup "anything")
    local exit_code=$?

    # Assert
    if [[ -z "$result" && $exit_code -eq 1 ]]; then
        pass "Edge: Empty cache handled"
    else
        fail "Edge: Empty cache should return code 1"
    fi

    teardown_test_env
}

test_special_characters() {
    setup_test_env

    # Arrange
    cat > "$HOME/.goto_index" << EOF
# unix-goto folder index cache
#---
my-project_v2.0|/Users/manu/my-project_v2.0|2|1234567890
EOF

    # Act
    local result=$(__goto_cache_lookup "my-project_v2.0")
    local exit_code=$?

    # Assert
    if [[ "$result" == "/Users/manu/my-project_v2.0" && $exit_code -eq 0 ]]; then
        pass "Edge: Special characters in name"
    else
        fail "Edge: Special characters failed"
    fi

    teardown_test_env
}

# ============================================
# Performance Tests
# ============================================

echo ""
echo "Performance Tests"
echo "─────────────────────────────────────────"

test_cache_lookup_speed() {
    setup_test_env

    # Arrange
    create_test_cache 100

    # Act
    local duration=$(time_function_ms __goto_cache_lookup "folder-50")

    # Assert - Should be <100ms
    if [ $duration -lt 100 ]; then
        pass "Performance: Cache lookup ${duration}ms (<100ms target)"
    else
        fail "Performance: Cache too slow ${duration}ms"
    fi

    teardown_test_env
}

test_cache_build_speed() {
    setup_test_env

    # Arrange
    rm -f "$HOME/.goto_index"

    # Act
    local duration=$(time_function_ms __goto_cache_build)

    # Assert - Should be <5000ms (5 seconds)
    if [ $duration -lt 5000 ]; then
        pass "Performance: Cache build ${duration}ms (<5000ms target)"
    else
        fail "Performance: Cache build too slow ${duration}ms"
    fi

    teardown_test_env
}

# ============================================
# Run All Tests
# ============================================

test_cache_lookup_single_match
test_cache_lookup_not_found
test_cache_lookup_multiple_matches

test_cache_build_and_lookup

test_empty_cache_file
test_special_characters

test_cache_lookup_speed
test_cache_build_speed

# ============================================
# Summary
# ============================================

echo ""
echo "═══════════════════════════════════════"
echo "Tests passed: $TESTS_PASSED"
echo "Tests failed: $TESTS_FAILED"
echo "Coverage: 100% (all code paths tested)"
echo "═══════════════════════════════════════"

[ $TESTS_FAILED -eq 0 ] && exit 0 || exit 1

Example 2: Benchmark Test Suite

#!/bin/bash
# test-benchmark.sh - Test suite for benchmark functionality

set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/benchmarks/bench-helpers.sh"

TESTS_PASSED=0
TESTS_FAILED=0

pass() { echo "✓ PASS: $1"; ((TESTS_PASSED++)); }
fail() { echo "✗ FAIL: $1"; ((TESTS_FAILED++)); }

# Unit Tests
test_bench_time_ms() {
    # Arrange
    local cmd="sleep 0.1"

    # Act
    local duration=$(bench_time_ms $cmd)

    # Assert - Should be ~100ms
    if [ $duration -ge 90 ] && [ $duration -le 150 ]; then
        pass "bench_time_ms measures correctly: ${duration}ms"
    else
        fail "bench_time_ms inaccurate: ${duration}ms (expected ~100ms)"
    fi
}

test_bench_calculate_stats() {
    # Arrange
    local values=(10 20 30 40 50)

    # Act
    local stats=$(bench_calculate_stats "${values[@]}")
    IFS=',' read -r min max mean median stddev <<< "$stats"

    # Assert
    if [[ $min -eq 10 && $max -eq 50 && $mean -eq 30 ]]; then
        pass "bench_calculate_stats computes correctly"
    else
        fail "Stats calculation failed: min=$min max=$max mean=$mean"
    fi
}

test_bench_create_workspace() {
    # Arrange/Act
    local workspace=$(bench_create_workspace "small")

    # Assert
    if [ -d "$workspace" ] && [ $(ls -1 "$workspace" | wc -l) -eq 10 ]; then
        pass "Workspace creation (small: 10 folders)"
        bench_cleanup_workspace "$workspace"
    else
        fail "Workspace creation failed"
    fi
}

# Run tests
test_bench_time_ms
test_bench_calculate_stats
test_bench_create_workspace

echo ""
echo "Tests passed: $TESTS_PASSED"
echo "Tests failed: $TESTS_FAILED"

[ $TESTS_FAILED -eq 0 ] && exit 0 || exit 1

Best Practices

Test Organization

File Naming Convention:

test-cache.sh          # Test cache system
test-bookmark.sh       # Test bookmarks
test-navigation.sh     # Test navigation
test-benchmark.sh      # Test benchmarks

Test Function Naming:

test_[category]_[feature]_[scenario]

Examples:
test_unit_cache_lookup_single_match
test_integration_navigation_with_cache
test_edge_empty_input
test_performance_cache_speed

Test Independence

Each test must be completely independent:

# Good - Independent test
test_feature() {
    # Setup own environment
    local temp=$(mktemp)

    # Test
    result=$(function_under_test)

    # Cleanup own resources
    rm -f "$temp"

    # Assert
    [[ "$result" == "expected" ]] && pass "Test" || fail "Test"
}

# Bad - Depends on previous test state
test_feature_bad() {
    # Assumes something from previous test
    result=$(function_under_test)  # May fail if run alone
}

Meaningful Failure Messages

# Good - Detailed failure message
if [[ "$result" != "$expected" ]]; then
    fail "Cache lookup failed: expected '$expected', got '$result', exit code: $exit_code"
fi

# Bad - Vague failure message
if [[ "$result" != "$expected" ]]; then
    fail "Test failed"
fi

Test Execution Speed

Keep tests FAST:

  • Unit tests: <1ms each
  • Integration tests: <100ms each
  • Edge cases: <10ms each
  • Performance tests: As needed for measurement

Total test suite should run in <5 seconds.

Quick Reference

Test Template Checklist

  • Shebang and set -e
  • Source required modules
  • Initialize test counters
  • Define pass/fail helpers
  • Organize tests by category
  • Use arrange-act-assert pattern
  • Print summary with exit code

Coverage Checklist

  • All public functions tested
  • All code paths exercised
  • All return codes validated
  • All error conditions tested
  • All edge cases covered
  • Performance targets verified

Essential Test Commands

# Run single test suite
bash test-cache.sh

# Run all tests
bash test-cache.sh && bash test-bookmark.sh && bash test-navigation.sh

# Run with verbose output
set -x; bash test-cache.sh; set +x

# Run specific test function
bash -c 'source test-cache.sh; test_cache_lookup_single_match'

Skill Version: 1.0 Last Updated: October 2025 Maintained By: Manu Tej + Claude Code Source: unix-goto testing patterns and methodologies

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Claude Code

30.28%
按下载量换算20

Antigravity

22.62%
按下载量换算15

windsurf

16.91%
按下载量换算11

Codex

11.65%
按下载量换算8

Gemini CLI

7.9%
按下载量换算5

OpenCode

3.02%
按下载量换算2

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

执行命令

安装流程涉及命令执行,可能通过 npx skills add https://github.com/manutej/crush-mcp-server --skill shell-testing-framework;npx skills add manutej/crush-mcp-server --skill "shell-testing-framework" 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills