How to Test Properties with Random Inputs in Python

Write a simple property-based test in Python using random string generation to verify that string invariants like reverse-twice identity and uppercase idempotence always hold.

Medium Python 3.9+ Aug 9, 2026 Testing & modern typing 12 views 0 copies

Python code

29 lines
Python 3.9+
import random
import string


def generate_random_string(length: int) -> str:
    """Generate a random alphanumeric string of given length."""
    chars = string.ascii_letters + string.digits
    return "".join(random.choice(chars) for _ in range(length))


def reverse_twice_is_identity(s: str) -> bool:
    """Property: reversing a string twice returns the original."""
    return s[::-1][::-1] == s


def uppercase_is_idempotent(s: str) -> bool:
    """Property: applying uppercase twice is the same as once."""
    return s.upper().upper() == s.upper()


if __name__ == "__main__":
    random.seed(42)
    test_cases = [generate_random_string(random.randint(1, 20)) for _ in range(100)]
    
    reverse_results = all(reverse_twice_is_identity(s) for s in test_cases)
    uppercase_results = all(uppercase_is_idempotent(s) for s in test_cases)
    
    print(f"Reverse-twice invariant holds: {reverse_results}")
    print(f"Uppercase-idempotence invariant holds: {uppercase_results}")

Output

stdout
Reverse-twice invariant holds: True
Uppercase-idempotence invariant holds: True

How it works

This code uses random and string from the standard library to generate random alphanumeric strings of varying lengths. The reverse_twice_is_identity function checks that reversing a string twice returns the original, which is a fundamental invariant of string reversal. The uppercase_is_idempotent function verifies that applying upper() twice produces the same result as applying it once, ensuring idempotence. By running these checks across 100 random test cases with a seeded random number generator, the tests are reproducible. Using all() over the list of boolean results confirms that every generated case passes the invariant.

Common mistakes

  • Forgetting to seed the random number generator, which makes the test non-reproducible
  • Using a fixed-length string, which reduces coverage of edge cases like empty strings
  • Testing only happy-path inputs instead of randomized or boundary conditions
  • Assuming built-in methods are always idempotent without verifying with tests

Variations

  1. Use the `hypothesis` library's `@given` decorator to generate random strings automatically
  2. Add an empty string to the test cases to verify invariants hold for the boundary case

Real-world use cases

  • Verifying data normalization functions always return consistent results regardless of input order or duplication.
  • Testing serialization and deserialization round-trips in APIs to ensure no data corruption occurs.
  • Automating regression checks for string formatting logic in logging or report generation systems.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Testing & modern typing

Related tutorials and quizzes for this topic.