New to Claude Skills? Learn how to install them →

trailofbits on GitHub

Property-Based Testing

Free

Enhance your testing strategy with property-based testing guidance.

by trailofbits6.5k stars on trailofbits/skills
5 views
Updated Aug 10, 2026
Get this skill

Free · Opens the source repo

What Property-Based Testing does

Property-based testing (PBT) is a testing methodology that focuses on defining properties of your code and generating a wide range of test cases to validate those properties. This skill provides comprehensive guidance on how to effectively implement PBT across multiple programming languages and smart contracts. It is particularly useful when dealing with complex serialization, parsing, and validation patterns where traditional example-based tests may fall short. By using this skill, developers can ensure that their code is robust and handles edge cases that might not be considered in conventional testing approaches.

The skill includes a decision tree that helps users determine when to apply PBT based on the patterns detected in their code. For instance, it identifies high-priority scenarios such as serialization pairs, pure functions, and smart contract invariants where PBT can provide significant coverage. Additionally, the skill offers a property catalog that outlines various properties like roundtrip, idempotence, and invariants, along with their corresponding formulas and use cases. This structured approach enables developers to systematically apply PBT principles to their testing efforts.

Users can also find references for generating tests, designing features, and interpreting test failures, making this skill a valuable resource throughout the development lifecycle. Whether you are writing new tests, reviewing existing ones, or designing new features, this skill equips you with the necessary tools and insights to leverage PBT effectively. It is especially beneficial for teams working with complex data structures or algorithms, ensuring that their testing strategies are both comprehensive and efficient.

In summary, this skill is designed for developers and designers who want to elevate their testing practices by incorporating property-based testing principles. It provides actionable guidance and resources to help ensure that code is thoroughly tested against a wide range of scenarios, ultimately leading to higher quality software.

When to use it

Use this skill during development when you encounter serialization, parsing, or validation patterns that benefit from property-based testing.

When not to use it

Avoid this skill for simple CRUD operations, one-off scripts, or situations where specific example cases are sufficient and well-understood.

What you can build with it

Testing Serialization Logic

When developing a system that involves encoding and decoding data, use this skill to apply property-based testing for roundtrip validation.

Validating Data Parsers

For applications that parse various data formats, leverage this skill to ensure your parsers handle a wide range of inputs correctly.

Reviewing Smart Contracts

When auditing smart contracts, use this skill to apply property-based testing to verify state invariants and access control mechanisms.

How to install Property-Based Testing

View source

1. Install with the skills CLI

npx skills add trailofbits/skills/property-based-testing --agent claude-code

2. Or install it manually

Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.

Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs

Inside SKILL.md

Written by trailofbits

Property-Based Testing Guide

Use this skill proactively during development when you encounter patterns where PBT provides stronger coverage than example-based tests.

When to Invoke (Automatic Detection)

Invoke this skill when you detect:

  • Serialization pairs: encode/decode, serialize/deserialize, toJSON/fromJSON, pack/unpack
  • Parsers: URL parsing, config parsing, protocol parsing, string-to-structured-data
  • Normalization: normalize, sanitize, clean, canonicalize, format
  • Validators: is_valid, validate, check_* (especially with normalizers)
  • Data structures: Custom collections with add/remove/get operations
  • Mathematical/algorithmic: Pure functions, sorting, ordering, comparators
  • Smart contracts: Solidity/Vyper contracts, token operations, state invariants, access control

Priority by pattern:

PatternPropertyPriority
encode/decode pairRoundtripHIGH
Pure functionMultipleHIGH
ValidatorValid after normalizeMEDIUM
Sorting/orderingIdempotence + orderingMEDIUM
NormalizationIdempotenceMEDIUM
Builder/factoryOutput invariantsLOW
Smart contractState invariantsHIGH

When NOT to Use

Do NOT use this skill for:

  • Simple CRUD operations without transformation logic
  • One-off scripts or throwaway code
  • Code with side effects that cannot be isolated (network calls, database writes)
  • Tests where specific example cases are sufficient and edge cases are well-understood
  • Integration or end-to-end testing (PBT is best for unit/component testing)

Property Catalog (Quick Reference)

PropertyFormulaWhen to Use
Roundtripdecode(encode(x)) == xSerialization, conversion pairs
Idempotencef(f(x)) == f(x)Normalization, formatting, sorting
InvariantProperty holds before/afterAny transformation
Commutativityf(a, b) == f(b, a)Binary/set operations
Associativityf(f(a,b), c) == f(a, f(b,c))Combining operations
Identityf(x, identity) == xOperations with neutral element
Inversef(g(x)) == xencrypt/decrypt, compress/decompress
Oraclenew_impl(x) == reference(x)Optimization, refactoring
Easy to Verifyis_sorted(sort(x))Complex algorithms
No ExceptionNo crash on valid inputBaseline property

Strength hierarchy (weakest to strongest): No Exception → Type Preservation → Invariant → Idempotence → Roundtrip

Decision Tree

Based on the current task, read the appropriate section:

TASK: Writing new tests
  → Read [{baseDir}/references/generating.md]({baseDir}/references/generating.md) (test generation patterns and examples)
  → Then [{baseDir}/references/strategies.md]({baseDir}/references/strategies.md) if input generation is complex

TASK: Designing a new feature
  → Read [{baseDir}/references/design.md]({baseDir}/references/design.md) (Property-Driven Development approach)

TASK: Code is difficult to test (mixed I/O, missing inverses)
  → Read [{baseDir}/references/refactoring.md]({baseDir}/references/refactoring.md) (refactoring patterns for testability)

TASK: Reviewing existing PBT tests
  → Read [{baseDir}/references/reviewing.md]({baseDir}/references/reviewing.md) (quality checklist and anti-patterns)

TASK: Test failed, need to interpret
  → Read [{baseDir}/references/interpreting-failures.md]({baseDir}/references/interpreting-failures.md) (failure analysis and bug classification)

TASK: Need library reference
  → Read [{baseDir}/references/libraries.md]({baseDir}/references/libraries.md) (PBT libraries by language, includes smart contract tools)

How to Suggest PBT

When you detect a high-value pattern while writing tests, offer PBT as an option:

"I notice encode_message/decode_message is a serialization pair. Property-based testing with a roundtrip property would provide stronger coverage than example tests. Want me to use that approach?"

If codebase already uses a PBT library (Hypothesis, fast-check, proptest, Echidna), be more direct:

"This codebase uses Hypothesis. I'll write property-based tests for this serialization pair using a roundtrip property."

If user declines, write good example-based tests without further prompting.

When NOT to Use PBT

  • Simple CRUD without complex validation
  • UI/presentation logic
  • Integration tests requiring complex external setup
  • Prototyping where requirements are fluid
  • User explicitly requests example-based tests only

Red Flags

  • Recommending trivial getters/setters
  • Missing paired operations (encode without decode)
  • Ignoring type hints (well-typed = easier to test)
  • Overwhelming user with candidates (limit to top 5-10)
  • Being pushy after user declines

Rationalizations to Reject

Do not accept these shortcuts:

  • "Example tests are good enough" - If serialization/parsing/normalization is involved, PBT finds edge cases examples miss
  • "The function is simple" - Simple functions with complex input domains (strings, floats, nested structures) benefit most from PBT
  • "We don't have time" - PBT tests are often shorter than comprehensive example suites
  • "It's too hard to write generators" - Most PBT libraries have excellent built-in strategies; custom generators are rarely needed
  • "The test failed, so it's a bug" - Failures require validation; see interpreting-failures.md
  • "No crash means it works" - "No exception" is the weakest property; always push for stronger guarantees

Frequently asked questions about Property-Based Testing

Similar skills