Back to Testing & Quality Assurance

property-based-testing

testingproperty-based testingPBTcode qualitysoftware engineeringtest automationsmart contractssecurity testing
5.7k📄 CC-BY-SA-4.0🕒 2026-06-15Source ↗

Install this skill

npx skills add trailofbits/skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

Property-based testing moves beyond static test cases by generating randomized inputs to verify that specific logic invariants hold true. Instead of writing individual assertions for expected outputs, this approach defines universal rules—such as idempotence or round-trip consistency—that a function must satisfy under any input. The testing engine identifies edge cases, boundary conditions, and unexpected data types that humans often miss when authoring manual examples. It excels in verifying complex transformations, parsers, and state-heavy logic where manual test coverage remains superficial. By identifying the smallest possible failing input for a discovered invariant, this methodology provides highly targeted feedback for debugging, ensuring that underlying core logic remains stable even when confronted with extreme or randomized data configurations.

When to Use This Skill

  • Validating serialization logic for JSON or binary protocol formats
  • Checking complex data sanitization and normalization routines
  • Verifying algorithmic outputs like sort order or set membership
  • Testing smart contract state transitions and access controls

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • How do I test this serialization logic more thoroughly?
  • Can you help me verify these data sanitization functions?
  • These unit tests miss too many edge cases; what can I use?
  • How can I prove this sorting algorithm is always correct?
  • I need to check if my encode/decode pair works for all inputs.

Pro Tips

  • 💡Start by identifying the simplest properties of your code's behavior, then gradually add more complex invariants. This iterative approach makes property definition more manageable.
  • 💡Combine property-based tests with traditional example-based unit tests. PBT excels at finding unexpected inputs, while example tests ensure specific, known-good scenarios are handled correctly.
  • 💡When a property-based test fails, leverage the 'shrinking' mechanism provided by PBT frameworks. This feature automatically finds the smallest input that causes the failure, significantly speeding up debugging.
  • 💡Focus on pure functions and idempotent operations first. Their predictable nature makes defining properties straightforward, providing immediate value and building confidence in PBT.

What this skill does

  • Automatic generation of valid and invalid input data
  • Identification of minimal reproduction inputs for failing tests
  • Verification of system-wide invariants and mathematical properties
  • Validation of symmetry in serialization and encoding processes
  • Regression testing via state-machine analysis

When not to use it

  • Simple CRUD operations lacking complex data transformation
  • Codebases dominated by heavy I/O or external network dependencies
  • UI components or visual presentation logic

Example workflow

  1. Identify a pure function or stateful operation suitable for invariants
  2. Define the expected properties, such as round-trip or idempotence
  3. Select an appropriate library compatible with the current language
  4. Configure input generators to match the data schema
  5. Run the test suite to observe randomized execution
  6. Refine logic if the generator identifies a counter-example

Prerequisites

  • Functional code structure with low I/O side effects
  • Clear definition of expected data types and constraints

Pitfalls & limitations

  • !Defining invariants that are too broad, leading to false positives
  • !Excessive execution time if the input space is not constrained
  • !Over-engineering simple logic that only requires one or two static cases

FAQ

Does property-based testing replace unit tests?
No, it complements them. While unit tests confirm expected results for specific scenarios, property-based tests explore a much wider space of potential inputs.
Can I use this for non-deterministic code?
It is best used for pure, deterministic functions. Non-deterministic code often requires mocking or refactoring to isolate the logic before effective testing can occur.
How do I know which property to test?
Look for symmetries. If you have an operation and its inverse, use round-trip. If an operation should not change the result after a second application, use idempotence.

How it compares

Unlike manual testing which relies on human intuition to predict edge cases, property-based testing uses algorithmic generation to exhaustively explore possible input states automatically.

Source & trust

5.7k stars📄 CC-BY-SA-4.0🕒 Updated 2026-06-15
📄 Full skill instructions — original source: trailofbits/skills
# 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:**

| Pattern | Property | Priority |
|---------|----------|----------|
| encode/decode pair | Roundtrip | HIGH |
| Pure function | Multiple | HIGH |
| Validator | Valid after normalize | MEDIUM |
| Sorting/ordering | Idempotence + ordering | MEDIUM |
| Normalization | Idempotence | MEDIUM |
| Builder/factory | Output invariants | LOW |
| Smart contract | State invariants | HIGH |

## 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)

| Property | Formula | When to Use |
|----------|---------|-------------|
| **Roundtrip** | decode(encode(x)) == x | Serialization, conversion pairs |
| **Idempotence** | f(f(x)) == f(x) | Normalization, formatting, sorting |
| **Invariant** | Property holds before/after | Any transformation |
| **Commutativity** | f(a, b) == f(b, a) | Binary/set operations |
| **Associativity** | f(f(a,b), c) == f(a, f(b,c)) | Combining operations |
| **Identity** | f(x, identity) == x | Operations with neutral element |
| **Inverse** | f(g(x)) == x | encrypt/decrypt, compress/decompress |
| **Oracle** | new_impl(x) == reference(x) | Optimization, refactoring |
| **Easy to Verify** | is_sorted(sort(x)) | Complex algorithms |
| **No Exception** | No crash on valid input | Baseline 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: 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

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/property-based-testing/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/trailofbits/skills/property-based-testing/SKILL.md
  • Cursor: ~/.cursor/skills/trailofbits/skills/property-based-testing/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/trailofbits/skills/property-based-testing/SKILL.md

🚀 Install with CLI:
npx skills add trailofbits/skills

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid testing & quality assurance issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Testing & Quality Assurance and is published by Trail of Bits, maintained in trailofbits/skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.