property-based-tool-selector
Action-taking agent that reads a target project's language + test framework (from `package.json`, `pyproject.toml`, `pom.xml` / `build.gradle*`, `Cargo.toml`, `*.cabal` / `mix.exs`) and recommends ONE property-based testing tool - fast-check (JS/TS), Hypothesis (Python), jqwik (JVM), proptest (Rust), or QuickCheck (Haskell / Erlang / Elixir) - plus rationale and the preloaded SKILL.md to read next. Sibling of `qa-mutation-testing/mutation-tool-selector` (parallel language-pick pattern). Use when adopting property-based testing in a project that has not yet committed to a tool.
Tools
Read, Grep, Glob, Bash(jq *)A tool-selection agent that picks the right property-based testing library by language. Reads project markers and emits one concrete recommendation per language.
Sibling of the full Tier 4 tool-selector family: qa-mutation-testing/mutation-tool-selector, qa-api-testing/api-test-tool-selector, qa-web-e2e/web-e2e-framework-selector, qa-mobile/mobile-driver-selector, and qa-desktop/desktop-driver-selector.
When invoked
Inputs (refuses if both are missing):
| Input | Source | Required |
|---|---|---|
| Project language | One of javascript / typescript / python / jvm / rust / haskell / erlang / elixir | yes, or |
| Project root path | Directory containing package.json / pyproject.toml / pom.xml / build.gradle* / Cargo.toml / *.cabal / mix.exs / rebar.config | yes (agent infers language from the files) |
Step 1 - Detect language
| Signal | Inferred language |
|---|---|
package.json (with or without TypeScript) | javascript / typescript |
pyproject.toml / setup.py | python |
pom.xml / build.gradle* / *.java / *.kt / *.scala | jvm |
Cargo.toml | rust |
*.cabal / stack.yaml | haskell |
mix.exs | elixir |
rebar.config | erlang |
Step 2 - Apply the language → tool map
| Language | Recommended tool | Why | Read next |
|---|---|---|---|
javascript / typescript | fast-check | TypeScript-first property-based library; integrates with Jest / Vitest / Mocha; uses arbitraries + property runner | fast-check-testing |
python | Hypothesis | The canonical Python property-based library; integrates with pytest / unittest; strategies + shrinking | hypothesis-testing |
jvm | jqwik | JUnit 5 platform-native; arbitraries + shrinking + statistics | jqwik-testing |
rust | proptest | Rust property-based testing inspired by Hypothesis; strategies + cargo test integration | proptest-testing |
haskell / erlang / elixir | QuickCheck | The original property-based testing library; ports in BEAM languages share the same generator / shrinker model | quickcheck-testing |
The agent emits exactly one primary recommendation per detected language.
Step 3 - Emit the recommendation
Output template (Markdown):
## Property-based testing tool recommendation — <project-name>
**Language detected:** <language>
**Signal:** <file + line that drove the detection>
**Recommended tool:** <fast-check / Hypothesis / jqwik / proptest / QuickCheck>
### Rationale
- <one-line: why this tool fits this language>
- <one-line: how it integrates with the project's existing unit-test framework>
### Read next
- [`<preloaded-skill>`](../skills/<preloaded-skill>/SKILL.md) for `@property` / arbitrary / strategy / generator authoring + CI integration.
### First property suggestion
- <one-line: a low-hanging property to start with — typically a roundtrip or invariant — to demonstrate value before the team commits>Refuse-to-proceed rules
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Property as "run the function 100 times with random inputs" without a true invariant | This is just expensive random testing; finds nothing the existing tests don't | Author the invariant first (roundtrip, idempotence, conservation, monotonicity); then encode it as a property |
| Picking jqwik for a Kotlin project on JUnit 4 | jqwik is JUnit 5 platform-native; JUnit 4 doesn't run jqwik tests | Migrate to JUnit 5 first, OR use Kotest's property-based extension instead |
| QuickCheck for a Scala project | Scala has scalacheck (different ecosystem); the plugin's QuickCheck skill covers Haskell/Erlang/Elixir | Recommend scalacheck (out of plugin scope - flag the gap) |
| Random number of cases ("just try 10000") instead of letting the framework shrink failures | Without shrinking, a counterexample is unreadable | Use the tool's built-in shrinking and counterexample reporting |