plugins/languages/bash/skills/testing/SKILL.md
Bash testing conventions using bats-core (Bash Automated Testing System): test layout, setup/teardown, run/assert helpers, bats-assert / bats-file / bats-support libraries, mocking commands via PATH override, coverage with kcov, and CI integration. Use when designing test suites for shell scripts, validating CLI behavior, or hardening release scripts. Triggers on "bats 测试", "shell 单元测试", "bats-core", "kcov bash", "shell 脚本测试", "mock command".
npx skillsauth add lazygophers/ccplugin bash-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| 工具 | 用途 | 最低版本 | |------|------|---------| | bats-core | 测试框架 | 1.11+ | | bats-assert | 断言库 | latest | | bats-support | 错误输出支撑 | latest | | bats-file | 文件断言 | latest | | kcov | 行覆盖率 | 42+ | | shellcheck | 静态检查 | 0.10+ | | shfmt | 格式化 | 3.8+ |
project/
├── bin/myscript
├── lib/
│ ├── util.sh
│ └── parser.sh
├── tests/
│ ├── test_helper/
│ │ ├── bats-support/
│ │ ├── bats-assert/
│ │ └── bats-file/
│ ├── common.bash # 共享 helper
│ ├── unit/
│ │ ├── util.bats
│ │ └── parser.bats
│ └── integration/
│ └── cli.bats
└── .bats.yaml
#!/usr/bin/env bats
# tests/unit/parser.bats
load '../common' # 加载共享 helper(无扩展名)
setup() {
load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
load 'test_helper/bats-file/load'
# 项目根入 PATH
PROJECT_ROOT="$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)"
PATH="${PROJECT_ROOT}/bin:${PATH}"
# 隔离 HOME / 临时目录
TMPDIR="$(mktemp -d)"
export TMPDIR
}
teardown() {
[[ -d "${TMPDIR}" ]] && rm -rf -- "${TMPDIR}"
}
@test "parse_count: numeric input" {
run parse_count "42"
assert_success
assert_output "42"
}
@test "parse_count: rejects non-numeric" {
run parse_count "abc"
assert_failure
assert_output --partial "invalid"
}
@test "myscript --help shows usage" {
run myscript --help
assert_success
assert_line --index 0 "Usage: myscript [options]"
}
@test "creates output file" {
run myscript --out "${TMPDIR}/out.txt"
assert_success
assert_file_exist "${TMPDIR}/out.txt"
assert_file_contains "${TMPDIR}/out.txt" "done"
}
# run 捕获 stdout/stderr/status
run command args
# $output — 合并 stdout+stderr
# $status — 退出码
# ${lines[@]} — output 按行
# $stderr / $stdout(bats 1.10+: run --separate-stderr)
run --separate-stderr myscript --bad-flag
assert_failure 2
assert_equal "$stderr" "error: bad flag"
常用断言(bats-assert):
assert_success
assert_failure [exit_code]
assert_output "exact"
assert_output --partial "substr"
assert_output --regexp '^[0-9]+$'
assert_line --index 0 "first line"
refute_output "bad"
assert_equal "$actual" "$expected"
# 在 PATH 前置目录放伪装可执行文件
setup() {
MOCK_BIN="$(mktemp -d)"
PATH="${MOCK_BIN}:${PATH}"
cat >"${MOCK_BIN}/curl" <<'EOF'
#!/usr/bin/env bash
echo '{"status":"ok"}'
exit 0
EOF
chmod +x "${MOCK_BIN}/curl"
}
@test "fetches data via curl" {
run fetch_status
assert_success
assert_output --partial "ok"
}
kcov \
--include-pattern=.sh,/bin/myscript \
--exclude-pattern=tests/ \
coverage \
bats tests/
# 打开 coverage/index.html 查看
name: bash-test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: install tools
run: |
sudo apt-get update
sudo apt-get install -y bats shellcheck shfmt kcov
- name: shellcheck
run: shellcheck bin/* lib/*.sh
- name: shfmt
run: shfmt -d -i 4 -ci bin/ lib/
- name: bats
run: bats --recursive tests/
- name: coverage
run: kcov --include-pattern=.sh coverage bats tests/
TMPDIR、HOME、PATH;teardown 清理。bats-assert 而非 [[ $output == ... ]]。trap 清理、信号处理。tools
--- name: trellisx-workspace description: 维护 `.trellis/task.md` 任务看板 —— trellis 缺的跨任务总览。**一个表格, 一行一个任务**, 列为 id/名称/描述/状态/阶段/进度/worktree (状态/阶段中文显示)。在 task create/start/阶段切换/archive 后**及时更新**对应行; 并**自动清理超 7 天的已完成行**防膨胀。保持看板与 task.json 实时一致。 when_to_use: 维护 / 创建 / 更新 `.trellis/task.md` 任务看板时; task 生命周期任一节点 (create/start/阶段推进/archive) 之后同步看板时; 用户问"当前有哪些任务 / 任务进度 / 任务看板"时。被 trellisx-flow 与 trellisx-apply 注入的流程引用。 user-invocable: true argument-hint: [show|update|sync|cleanup ...] [task id] arguments:
testing
强制以 Trellis task 闭环处理用户指定的请求 (自判新建/并入 → plan→exec→check→finish 全程不跳步)。**仅用户显式主动调用** (/trellisx-flow 或明确要求"强制走 task 处理这个"); **禁止自动 / 被动 / 推断式调用** —— 不要因为某个请求"看起来该建 task"就自动触发本 skill, 那是 apply 注入的 no_task 倾向的职责。
testing
把 强推task + subtask拆分 + worktree隔离 + 闭环收尾 四维度增量注入当前项目 .trellis/ (workflow.md 的 no_task/planning/in_progress 块 + spec 背书文档 + trellis 生命周期 hook worktree 自动化)。强推 task 与闭环为纯 prompt 软约束 (非平台 hook 硬拦截)。**纯增量追加, 绝不替换 trellis 原生文本** (no_task 分类+征同意/check/finish/前缀全保留)。幂等 (marker 包裹)。
development
Claude Code 会话历史整理 — 扫 ~/.claude/projects/**/*.jsonl 全部 session transcripts, 提取学习增量 (用户校正/决策/踩坑/L0 规则) → 全局记忆库 ~/.cortex/.wiki/memory/. 默认 --apply 落盘 (--dry-run opt-in 仅出 JSON plan 预览). 与 cortex-extract (L4-inbox 内部) 互补.