property-based-test
Skill8 starsChanged 3 months agoMITView on GitHub
明示的に `property-based-test` を呼び出した場合のみ使用する。 Property-Based Testing(PBT)の自動設計・実装支援。テスト対象コードを静的分析し、 プロパティパターン選定・ジェネレータ合成・テストコード生成・実行・レポートを自動実行する。 フレームワーク自動検出。必要な場合だけ独立調査を並列実行する。
- Installs packages
In this repository20 other files it gives its agents.
- AGENTS.mdAGENTS.md
- agent-efficiency-auditSkill
- dry-codingSkill
- exploratory-testSkill
- graph-think-mapSkill
- guided-codeSkill
- handoffSkill
- issue-analysisSkill
- karin-infoSkill
- local-repo-finderSkill
- milestone-triageSkill
- pr-comment-planSkill
- pr-generatorSkill
- print-debugSkill
- private-isu-tuningSkill
- propose-pi-extensionsSkill
- research-questionerSkill
- review-codeSkill
- skill-zipSkill
- ts-lint-searcherSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 197
Metamorphic: search/query/filter/sort/数値計算で、入力変換と出力の関係が述べられる
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Property-Based Testing Skill
CONSTRAINT
mode: write # テストコードを生成・実行する
source_modification: false # テスト対象のソースコードは変更しない
output_scope: test_files_onlyINPUT_SCHEMA
arguments: "$ARGUMENTS"
arguments_format: "<target_path> [--focus 観点1,観点2]" # target_path 必須。空ならユーザーにファイルパスを確認する
focus_mapping:
"境界値|boundary": [invariant, metamorphic]
"エラー処理|error": [invariant, oracle]
"冪等性|idempotent": [idempotent]
"シリアライズ|serialize": [roundtrip]
"状態|state|stateful": [stateful]
"性能|performance": [oracle, metamorphic]
"代数|algebraic": [algebraic]
"全般|all": [ALL]EXECUTION_PIPELINE
Phase1:Analyze ──gate:data_ready──▶ Phase2:Design ──gate:plan_ready──▶ Phase3:Generate ──▶ Phase4:Execute ──▶ Phase5:Report各 gate は前フェーズの出力が後フェーズの入力要件を満たすことを検証する内部チェック。ユーザー確認ゲートは不要(自動実行)。
PHASE_1: ANALYZE
1.1 サブエージェント起動(条件付き)
小規模な対象や親の直接分析で十分な場合は、subagentを使わずに調査する。独立した成果物や競合仮説があり、調整コストを上回る場合のみ、必要なタスクだけを並列起動する。固定数を必須にしない。
候補タスク:
candidate_tasks:
- agent: Task(Explore)
id: agent_a
label: "対象コード静的分析"
prompt: |
{target_path} を読み込み、以下を構造化して返却せよ:
1. 全 public 関数/メソッドの一覧
各エントリ: {name, params: [{name, type, nullable, default}], return_type, is_pure, has_side_effects, mutates_state}
2. 関数ペア検出: {pairs: [{fn_a, fn_b, relation: "encode/decode"|"serialize/deserialize"|"to/from"|"write/read"}]}
3. 依存グラフ: {imports, internal_calls, external_calls}
4. 推定不変条件: [{function, invariant_description}]
- agent: Task(Explore)
id: agent_b
label: "テスト基盤調査"
prompt: |
プロジェクトルートから以下を特定せよ:
1. 言語: {lang: "typescript"|"python"|"rust"|"go"|"java"|"kotlin"|"ruby"}
2. テストFW: {test_framework, config_file, test_dir_pattern, test_file_pattern}
3. PBTライブラリ: {pbt_lib: string|null, version: string|null}
4. 既存テストスタイル: {sample_test_file, assertion_style, describe_pattern}
5. パッケージマネージャ: {manager, lockfile}1.2 フレームワーク解決
detection_rules:
typescript:
indicators: ["package.json", "tsconfig.json", ".ts files"]
test_fw_detect:
- {file: "jest.config.*", result: "jest"}
- {file: "vitest.config.*", result: "vitest"}
- {file: "package.json", key: "mocha", result: "mocha"}
pbt_lib_detect:
- {package: "fast-check", result: "fast-check"}
fallback_pbt: "fast-check"
install_cmd: "npm install --save-dev fast-check"
python:
indicators: ["setup.py", "pyproject.toml", "requirements*.txt", ".py files"]
test_fw_detect:
- {file: "pytest.ini|pyproject.toml[tool.pytest]|setup.cfg[tool:pytest]", result: "pytest"}
- {fallback: "unittest"}
pbt_lib_detect:
- {package: "hypothesis", result: "hypothesis"}
fallback_pbt: "hypothesis"
install_cmd: "pip install hypothesis"
rust:
indicators: ["Cargo.toml", ".rs files"]
test_fw_detect:
- {builtin: "cargo test", result: "cargo_test"}
pbt_lib_detect:
- {dep: "proptest", result: "proptest"}
fallback_pbt: "proptest"
install_cmd: 'Cargo.toml に追記: [dev-dependencies] proptest = "1"'
go:
indicators: ["go.mod", ".go files"]
test_fw_detect:
- {builtin: "go test", result: "go_test"}
pbt_lib_detect:
- {module: "pgregory.net/rapid", result: "rapid"}
fallback_pbt: "rapid"
install_cmd: "go get pgregory.net/rapid"
java:
indicators: ["pom.xml", "build.gradle", ".java files"]
test_fw_detect:
- {dep: "junit-jupiter", result: "junit5"}
pbt_lib_detect:
- {dep: "jqwik", result: "jqwik"}
fallback_pbt: "jqwik"
install_cmd: "pom.xml/build.gradle に jqwik 依存追加"
kotlin:
indicators: ["build.gradle.kts", ".kt files"]
test_fw_detect:
- {dep: "junit-jupiter|kotest", result: "junit5|kotest"}
pbt_lib_detect:
- {dep: "jqwik|kotest-property", result: "jqwik|kotest-property"}
fallback_pbt: "jqwik"
ruby:
indicators: ["Gemfile", ".rb files"]
test_fw_detect:
- {gem: "rspec", result: "rspec"}
- {fallback: "minitest"}
pbt_lib_detect:
- {gem: "rantly", result: "rantly"}
- {gem: "prop_check", result: "prop_check"}
fallback_pbt: "rantly"
install_cmd: "Gemfile に追記: gem 'rantly', group: :test"1.3 PBTライブラリ未導入時
IF pbt_lib == null:
1. ユーザーに確認:
"PBTライブラリ {fallback_pbt} が未導入です。インストールしますか?"
options: ["はい(推奨)", "いいえ(中断)"]
2. IF "はい": install_cmd を実行
3. IF "いいえ": 処理中断、理由を報告1.4 Phase1 出力スキーマ
# gate:data_ready の検証対象
phase1_output:
functions: [{name, params, return_type, is_pure, has_side_effects, mutates_state}]
function_pairs: [{fn_a, fn_b, relation}]
invariants: [{function, description}]
env:
lang: string
test_fw: string
pbt_lib: string
test_dir: string
test_file_pattern: string
assertion_style: string
focus_areas: string[] | null # --focus のパース結果PHASE_2: DESIGN
references/property-patterns.md のパターン選定アルゴリズムを適用する。
2.1 プロパティ選定アルゴリズム
各関数に対して、当てはまるパターンを以下の条件で選ぶ:
- Round-trip: encode/decode、serialize/deserialize、to/from、write/read の対がある
- Oracle: stdlib・素朴実装・旧版など参照実装がある
- Invariant: コレクション操作、または出力に制約がある
- Idempotent: 入力と出力の型が同じ純粋関数で、normalize/format/clean/trim/canonicalize/dedupe/sanitize の性質を持つ
- Stateful: 状態を変更する
- Metamorphic: search/query/filter/sort/数値計算で、入力変換と出力の関係が述べられる
- Algebraic: 結合則・交換則・単位元を持つ二項演算
優先順は roundtrip > oracle > invariant > idempotent / stateful > metamorphic > algebraic。--focus に合致するパターンは繰り上げる。1 関数あたり価値の高いものに絞り、網羅は目的にしない。
2.2 プロパティ仕様の構造化
# 各選定プロパティの出力フォーマット
property_spec:
id: "P{seq_number}"
pattern: "roundtrip|invariant|idempotent|oracle|metamorphic|algebraic|stateful"
target_functions: [string]
formal_definition: "∀ x ∈ Gen<T>: postcondition(x)"
precondition: "assume(x) 条件" | null
postcondition: "検証する不変条件"
generator_requirements:
input_types: [{param_name, type, constraints}]
edge_cases: [string]
expected_bug_class: "このプロパティが検出するバグの種類"
priority: integer # weight値PHASE_3: GENERATE
references/generator-patterns.md と references/framework-templates.md を参照。
3.1 ジェネレータ合成ルール
FOR EACH property IN selected_properties:
FOR EACH param IN property.generator_requirements.input_types:
generator = resolve_generator(param)
FUNCTION resolve_generator(param) -> GeneratorExpr:
MATCH param.type:
# プリミティブ型 → 組み込み
"integer" → gen.integer(param.constraints.min, param.constraints.max)
"float" → gen.float(param.constraints.min, param.constraints.max)
"string" → gen.string(param.constraints.minLen, param.constraints.maxLen)
"boolean" → gen.boolean()
# コレクション型 → 再帰合成
"Array<T>" → gen.array(resolve_generator(T), {minLength, maxLength})
"Map<K,V>" → gen.map(resolve_generator(K), resolve_generator(V))
"Set<T>" → gen.set(resolve_generator(T))
# nullable → oneOf合成
"T | null" → gen.oneOf(gen.constant(null), resolve_generator(T))
"T | undefined" → gen.option(resolve_generator(T))
# ドメイン型 → record合成
"Record{fields}" → gen.record({f.name: resolve_generator(f.type) for f in fields})
# Union型 → oneOf合成
"A | B | C" → gen.oneOf(resolve_generator(A), resolve_generator(B), resolve_generator(C))
# 列挙型 → constant選択
"Enum{values}" → gen.oneOf(...[gen.constant(v) for v in values])
# 依存型 → flatMap合成
"Dependent(a, f)" → resolve_generator(a).flatMap(a_val => f(a_val))
# エッジケース注入(frequency ラッピング)
WRAP WITH gen.frequency([
[75, base_generator],
[15, edge_case_generator(param.type)],
[10, extreme_value_generator(param.type)]
])3.2 テストコード生成
PROCEDURE generate_test_code(properties, env):
template = load_template(env.lang, env.pbt_lib) # references/framework-templates.md
style = env.assertion_style
test_file_path = resolve_test_path(env.test_dir, env.test_file_pattern, target_path)
code_blocks = []
FOR EACH prop IN properties:
code_blocks.append(template.render(
property_spec=prop,
generators=prop.generators,
assertion_style=style
))
output_file = assemble(
imports=template.imports(env.pbt_lib, target_path),
body=code_blocks,
config={numRuns: 100, seed: null, timeout: env.timeout_ms}
)
WRITE output_file TO test_file_path3.3 シュリンキング品質チェック
shrinking_rules:
- rule: "filter の使用を検出した場合"
check: "フィルタ通過率 > 10% を推定"
fix: "map ベースの制約埋め込みに書き換え"
- rule: "ジェネレータ外での値変換を検出した場合"
fix: "map でジェネレータ内に移動"
- rule: "深い flatMap チェーンを検出した場合(depth > 3)"
fix: "依存を減らすか、中間構造を導入"Phase 3の完了前に 強度チェックとジェネレータの現実性 を実施する。
PHASE_4: EXECUTE
PROCEDURE execute_tests(test_file_path, env):
cmd = MATCH env.lang:
"typescript" → "{npx|yarn} {jest|vitest} {test_file_path}"
"python" → "pytest {test_file_path} -v"
"rust" → "cargo test --test {test_name}"
"go" → "go test -run {test_func} -v {package}"
"java" → "mvn test -Dtest={test_class} | gradle test --tests {test_class}"
"ruby" → "bundle exec rspec {test_file_path}"
result = Bash(cmd)
IF result.exit_code != 0:
failures = parse_failures(result.output, env.pbt_lib)
FOR EACH failure IN failures:
analysis = classify_failure(failure)
# analysis.type ∈ {"true_bug", "false_positive", "generator_issue", "timeout"}
MATCH analysis.type:
"true_bug" → record_bug(failure.property, failure.counterexample, failure.shrunk_value), pin_defect(failure), re-run
"false_positive" → fix_property(failure.property), re-run
"generator_issue" → fix_generator(failure.generator), re-run
"timeout" → reduce_num_runs(failure.property), re-run
# re-run は最大2回まで実バグを確認したら 既知バグのpin手順 に従う。
PHASE_5: REPORT
report_schema:
header:
target: "{target_path}"
lang: "{env.lang}"
test_fw: "{env.test_fw} + {env.pbt_lib}"
num_runs_per_property: integer
total_execution_time: string
properties:
- id: "P1"
pattern: string
target_function: string
formal_definition: string
result: "PASS|FAIL"
counterexample: object | null # FAIL時のみ
shrunk_value: object | null # FAIL時のみ
bugs_found:
- property_id: string
severity: "critical|major|minor"
description: string
counterexample: object
shrunk_to: object
suggested_fix: string | null
pinned: boolean # falseなら判断待ちの理由を記載
generator_notes:
- param: string
strategy: string
edge_cases_included: [string]
shrinking_status: "auto|custom|none"
recommendations:
- type: "additional_property|generator_extension|coverage_gap"
description: string
priority: "high|medium|low"
test_file: "{test_file_path}"出力は上記スキーマに従った Markdown テーブル形式でユーザーに提示する。
REFERENCE_FILES
references:
- path: "references/property-patterns.md"
content: "7パターンの形式定義、適用述語、選定スコアリングルール"
- path: "references/generator-patterns.md"
content: "型代数に基づくジェネレータ合成規則、エッジケース分布仕様、シュリンキング不変条件"
- path: "references/framework-templates.md"
content: "6言語×PBTライブラリのコードテンプレート(検出ルール、import、assertion、config)"Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

