[{"data":1,"prerenderedAt":1539},["ShallowReactive",2],{"page-\u002Fproperty-based-fuzz-testing-strategies\u002F":3},{"id":4,"title":5,"body":6,"description":16,"extension":1533,"meta":1534,"navigation":186,"path":1535,"seo":1536,"stem":1537,"__hash__":1538},"content\u002Fproperty-based-fuzz-testing-strategies\u002Findex.md","Property-Based & Fuzz Testing Strategies",{"type":7,"value":8,"toc":1521},"minimark",[9,13,17,20,25,28,47,85,96,100,107,129,132,143,152,382,391,395,398,409,420,600,623,634,638,645,652,659,686,952,966,970,973,976,987,1009,1012,1016,1019,1025,1036,1055,1344,1347,1351,1354,1368,1384,1399,1406,1411,1469,1473,1479,1485,1491,1517],[10,11,5],"h1",{"id":12},"property-based-fuzz-testing-strategies",[14,15,16],"p",{},"Traditional example-based testing has served Python ecosystems well for decades, but as systems scale in complexity, combinatorial state spaces, and integration depth, hardcoded fixtures inevitably fail to capture the full spectrum of failure modes. Property-based testing (PBT) and fuzzing represent a paradigm shift from verifying specific inputs to validating system invariants across massive, automatically generated input domains. For mid-to-senior engineers and open-source maintainers, mastering these techniques is no longer optional; it is a prerequisite for shipping resilient, production-grade software.",[14,18,19],{},"This guide dissects the architectural foundations of property-driven validation, explores the Hypothesis ecosystem's advanced mechanics, contrasts structured PBT with coverage-guided fuzzing, and provides actionable strategies for CI\u002FCD integration, performance profiling, and anti-pattern avoidance.",[21,22,24],"h2",{"id":23},"paradigm-shift-from-example-based-to-property-driven-validation","Paradigm Shift: From Example-Based to Property-Driven Validation",[14,26,27],{},"Example-based testing relies on manually curated input-output pairs. While effective for deterministic happy-path verification and regression anchoring, it suffers from inherent combinatorial limitations. Engineers inevitably test the inputs they anticipate, leaving edge cases, boundary conditions, and unexpected type coercions unexamined. As system complexity grows, the number of required examples grows exponentially, leading to brittle test suites that are expensive to maintain yet statistically insignificant in coverage.",[14,29,30,31,35,36,39,40,43,44,46],{},"Property-based testing inverts this model. Instead of asserting ",[32,33,34],"code",{},"f(x) == y"," for specific ",[32,37,38],{},"x",", PBT asserts that ",[32,41,42],{},"f"," satisfies mathematical or behavioral invariants across an entire domain of ",[32,45,38],{},". These invariants often derive from algebraic properties:",[48,49,50,61,69,77],"ul",{},[51,52,53,57,58],"li",{},[54,55,56],"strong",{},"Idempotence:"," ",[32,59,60],{},"f(f(x)) == f(x)",[51,62,63,57,66],{},[54,64,65],{},"Commutativity:",[32,67,68],{},"f(a, b) == f(b, a)",[51,70,71,57,74],{},[54,72,73],{},"Associativity:",[32,75,76],{},"f(a, f(b, c)) == f(f(a, b), c)",[51,78,79,57,82],{},[54,80,81],{},"Inverse Operations:",[32,83,84],{},"decode(encode(x)) == x",[14,86,87,88,91,92,95],{},"The critical distinction lies in validation boundaries. Example-based tests typically verify state mutation (",[32,89,90],{},"assert db.count() == 1","). PBT focuses on behavioral guarantees (",[32,93,94],{},"assert transaction.atomicity_holds()","), decoupling test assertions from internal implementation details. This shift forces engineers to articulate system contracts explicitly, surfacing architectural ambiguities before they manifest in production. By treating tests as executable specifications rather than regression checklists, teams achieve higher fault-detection rates with fewer lines of test code, while simultaneously generating comprehensive documentation of expected system behavior.",[21,97,99],{"id":98},"core-mechanics-of-the-hypothesis-ecosystem","Core Mechanics of the Hypothesis Ecosystem",[14,101,102,103,106],{},"Hypothesis is the industry-standard PBT library for Python, designed to integrate seamlessly with ",[32,104,105],{},"pytest"," and modern type systems. Its architecture revolves around three core components: strategies, the test runner, and the shrinking engine.",[14,108,109,110,113,114,113,117,120,121,124,125,128],{},"Strategies define how input data is generated. Hypothesis provides type-aware primitives (",[32,111,112],{},"st.text()",", ",[32,115,116],{},"st.integers()",[32,118,119],{},"st.floats()",") that respect Python's numeric boundaries and Unicode normalization rules. Strategies are composable: ",[32,122,123],{},"st.dictionaries(keys=st.text(), values=st.integers())"," generates valid mapping structures without manual boilerplate. The ",[32,126,127],{},"@given"," decorator binds these strategies to test functions, transforming them into parameterized generators.",[14,130,131],{},"The true engineering value of Hypothesis lies in its shrinking algorithm. When a generated input triggers a failure, Hypothesis does not simply report the raw payload. It systematically reduces the input to the minimal counterexample that still reproduces the bug. This process involves iterative simplification: stripping characters from strings, reducing integer magnitudes, removing dictionary keys, and collapsing nested structures. Shrinking transforms cryptic stack traces into actionable, human-readable bug reports.",[14,133,134,135,138,139,142],{},"Reproducibility is guaranteed through deterministic seed control and a persistent example database. Hypothesis caches failing examples in ",[32,136,137],{},".hypothesis\u002Fexamples\u002F",", ensuring that discovered edge cases survive across test runs and developer machines. Combined with ",[32,140,141],{},"@seed()"," decorators, this enables exact replay of non-deterministic failures during debugging.",[14,144,145,146,148,149,151],{},"Hypothesis integrates natively with ",[32,147,105],{},"'s assertion rewriting engine. When a property fails, ",[32,150,105],{}," provides rich diff output, local variable inspection, and traceback formatting identical to standard unit tests. This eliminates context-switching overhead and allows teams to adopt PBT incrementally.",[153,154,159],"pre",{"className":155,"code":156,"language":157,"meta":158,"style":158},"language-python shiki shiki-themes github-light github-dark","import pytest\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.errors import Unsatisfiable\n\ndef merge_sorted_lists(a: list[int], b: list[int]) -> list[int]:\n \"\"\"Production function under test.\"\"\"\n result = []\n i = j = 0\n while i \u003C len(a) and j \u003C len(b):\n if a[i] \u003C= b[j]:\n result.append(a[i])\n i += 1\n else:\n result.append(b[j])\n j += 1\n result.extend(a[i:])\n result.extend(b[j:])\n return result\n\n@given(a=st.lists(st.integers(), min_size=0, max_size=20),\n b=st.lists(st.integers(), min_size=0, max_size=20))\n@settings(max_examples=100)\ndef test_merge_preserves_order_and_length(a, b):\n # Pre-condition: inputs must be sorted\n a_sorted = sorted(a)\n b_sorted = sorted(b)\n \n merged = merge_sorted_lists(a_sorted, b_sorted)\n \n # Property 1: Length preservation\n assert len(merged) == len(a) + len(b)\n \n # Property 2: Output is sorted\n assert merged == sorted(merged)\n \n # Property 3: Element multiset preservation\n assert sorted(merged) == sorted(a_sorted + b_sorted)\n","python","",[32,160,161,169,175,181,188,194,200,206,212,218,224,230,236,242,248,254,260,266,272,277,283,289,295,301,307,313,319,325,331,336,342,348,353,359,365,370,376],{"__ignoreMap":158},[162,163,166],"span",{"class":164,"line":165},"line",1,[162,167,168],{},"import pytest\n",[162,170,172],{"class":164,"line":171},2,[162,173,174],{},"from hypothesis import given, settings, strategies as st\n",[162,176,178],{"class":164,"line":177},3,[162,179,180],{},"from hypothesis.errors import Unsatisfiable\n",[162,182,184],{"class":164,"line":183},4,[162,185,187],{"emptyLinePlaceholder":186},true,"\n",[162,189,191],{"class":164,"line":190},5,[162,192,193],{},"def merge_sorted_lists(a: list[int], b: list[int]) -> list[int]:\n",[162,195,197],{"class":164,"line":196},6,[162,198,199],{}," \"\"\"Production function under test.\"\"\"\n",[162,201,203],{"class":164,"line":202},7,[162,204,205],{}," result = []\n",[162,207,209],{"class":164,"line":208},8,[162,210,211],{}," i = j = 0\n",[162,213,215],{"class":164,"line":214},9,[162,216,217],{}," while i \u003C len(a) and j \u003C len(b):\n",[162,219,221],{"class":164,"line":220},10,[162,222,223],{}," if a[i] \u003C= b[j]:\n",[162,225,227],{"class":164,"line":226},11,[162,228,229],{}," result.append(a[i])\n",[162,231,233],{"class":164,"line":232},12,[162,234,235],{}," i += 1\n",[162,237,239],{"class":164,"line":238},13,[162,240,241],{}," else:\n",[162,243,245],{"class":164,"line":244},14,[162,246,247],{}," result.append(b[j])\n",[162,249,251],{"class":164,"line":250},15,[162,252,253],{}," j += 1\n",[162,255,257],{"class":164,"line":256},16,[162,258,259],{}," result.extend(a[i:])\n",[162,261,263],{"class":164,"line":262},17,[162,264,265],{}," result.extend(b[j:])\n",[162,267,269],{"class":164,"line":268},18,[162,270,271],{}," return result\n",[162,273,275],{"class":164,"line":274},19,[162,276,187],{"emptyLinePlaceholder":186},[162,278,280],{"class":164,"line":279},20,[162,281,282],{},"@given(a=st.lists(st.integers(), min_size=0, max_size=20),\n",[162,284,286],{"class":164,"line":285},21,[162,287,288],{}," b=st.lists(st.integers(), min_size=0, max_size=20))\n",[162,290,292],{"class":164,"line":291},22,[162,293,294],{},"@settings(max_examples=100)\n",[162,296,298],{"class":164,"line":297},23,[162,299,300],{},"def test_merge_preserves_order_and_length(a, b):\n",[162,302,304],{"class":164,"line":303},24,[162,305,306],{}," # Pre-condition: inputs must be sorted\n",[162,308,310],{"class":164,"line":309},25,[162,311,312],{}," a_sorted = sorted(a)\n",[162,314,316],{"class":164,"line":315},26,[162,317,318],{}," b_sorted = sorted(b)\n",[162,320,322],{"class":164,"line":321},27,[162,323,324],{}," \n",[162,326,328],{"class":164,"line":327},28,[162,329,330],{}," merged = merge_sorted_lists(a_sorted, b_sorted)\n",[162,332,334],{"class":164,"line":333},29,[162,335,324],{},[162,337,339],{"class":164,"line":338},30,[162,340,341],{}," # Property 1: Length preservation\n",[162,343,345],{"class":164,"line":344},31,[162,346,347],{}," assert len(merged) == len(a) + len(b)\n",[162,349,351],{"class":164,"line":350},32,[162,352,324],{},[162,354,356],{"class":164,"line":355},33,[162,357,358],{}," # Property 2: Output is sorted\n",[162,360,362],{"class":164,"line":361},34,[162,363,364],{}," assert merged == sorted(merged)\n",[162,366,368],{"class":164,"line":367},35,[162,369,324],{},[162,371,373],{"class":164,"line":372},36,[162,374,375],{}," # Property 3: Element multiset preservation\n",[162,377,379],{"class":164,"line":378},37,[162,380,381],{}," assert sorted(merged) == sorted(a_sorted + b_sorted)\n",[14,383,384,385,390],{},"For a deeper exploration of strategy composition, database caching mechanics, and pytest integration patterns, consult the ",[386,387,389],"a",{"href":388},"\u002Fproperty-based-fuzz-testing-strategies\u002Fhypothesis-framework-fundamentals\u002F","Hypothesis Framework Fundamentals",".",[21,392,394],{"id":393},"advanced-property-design-patterns","Advanced Property Design Patterns",[14,396,397],{},"As test suites mature, engineers must move beyond primitive strategies to model domain-specific constraints and complex invariants. Advanced PBT requires deliberate strategy design to balance generation efficiency with constraint tightness.",[14,399,400,401,404,405,408],{},"Idempotence, commutativity, and inverse operation validation form the backbone of robust property design. Consider serialization pipelines: ",[32,402,403],{},"assert json.loads(json.dumps(obj)) == obj"," is a classic inverse property. However, floating-point precision, timezone normalization, and custom type coercion often break naive assumptions. Engineers must explicitly model these boundaries using ",[32,406,407],{},"st.floats(allow_nan=False, allow_infinity=False)"," or custom normalization strategies.",[14,410,411,412,415,416,419],{},"Custom strategies are implemented via ",[32,413,414],{},"@composite"," and ",[32,417,418],{},"draw()",". This pattern allows engineers to generate correlated data structures that respect business logic. For example, generating valid financial records requires synchronized timestamps, currency codes, and decimal precision constraints.",[153,421,423],{"className":155,"code":422,"language":157,"meta":158,"style":158},"from datetime import datetime, timedelta\nfrom hypothesis import strategies as st\nfrom hypothesis import given, settings\n\n@st.composite\ndef valid_iso_timestamps(draw: st.DrawFn, min_year: int = 2000, max_year: int = 2030) -> str:\n \"\"\"Generates valid ISO 8601 timestamps within a constrained range.\"\"\"\n base = draw(st.datetimes(min_year=min_year, max_year=max_year))\n offset_minutes = draw(st.integers(min_value=-1440, max_value=1440))\n tz_offset = timedelta(minutes=offset_minutes)\n aware_dt = base.replace(tzinfo=None) # Simplified for example\n return aware_dt.isoformat()\n\n@st.composite\ndef constrained_financial_record(draw: st.DrawFn) -> dict:\n \"\"\"Generates correlated transaction data with valid currency\u002Famount pairs.\"\"\"\n currency = draw(st.sampled_from([\"USD\", \"EUR\", \"GBP\"]))\n # Amount precision matches currency decimal places\n if currency == \"JPY\":\n amount = draw(st.integers(min_value=0, max_value=1_000_000))\n else:\n amount = draw(st.floats(min_value=0.01, max_value=100_000.00, allow_nan=False))\n return {\n \"currency\": currency,\n \"amount\": round(amount, 4),\n \"timestamp\": draw(valid_iso_timestamps()),\n \"id\": draw(st.uuids())\n }\n\n@given(record=constrained_financial_record())\n@settings(max_examples=500)\ndef test_financial_record_serialization(record: dict):\n # Validate domain invariants\n assert record[\"currency\"] in {\"USD\", \"EUR\", \"GBP\", \"JPY\"}\n assert record[\"amount\"] >= 0.0\n assert isinstance(record[\"id\"], str)\n",[32,424,425,430,435,440,444,449,454,459,464,469,474,479,484,488,492,497,502,507,512,517,522,526,531,536,541,546,551,556,561,565,570,575,580,585,590,595],{"__ignoreMap":158},[162,426,427],{"class":164,"line":165},[162,428,429],{},"from datetime import datetime, timedelta\n",[162,431,432],{"class":164,"line":171},[162,433,434],{},"from hypothesis import strategies as st\n",[162,436,437],{"class":164,"line":177},[162,438,439],{},"from hypothesis import given, settings\n",[162,441,442],{"class":164,"line":183},[162,443,187],{"emptyLinePlaceholder":186},[162,445,446],{"class":164,"line":190},[162,447,448],{},"@st.composite\n",[162,450,451],{"class":164,"line":196},[162,452,453],{},"def valid_iso_timestamps(draw: st.DrawFn, min_year: int = 2000, max_year: int = 2030) -> str:\n",[162,455,456],{"class":164,"line":202},[162,457,458],{}," \"\"\"Generates valid ISO 8601 timestamps within a constrained range.\"\"\"\n",[162,460,461],{"class":164,"line":208},[162,462,463],{}," base = draw(st.datetimes(min_year=min_year, max_year=max_year))\n",[162,465,466],{"class":164,"line":214},[162,467,468],{}," offset_minutes = draw(st.integers(min_value=-1440, max_value=1440))\n",[162,470,471],{"class":164,"line":220},[162,472,473],{}," tz_offset = timedelta(minutes=offset_minutes)\n",[162,475,476],{"class":164,"line":226},[162,477,478],{}," aware_dt = base.replace(tzinfo=None) # Simplified for example\n",[162,480,481],{"class":164,"line":232},[162,482,483],{}," return aware_dt.isoformat()\n",[162,485,486],{"class":164,"line":238},[162,487,187],{"emptyLinePlaceholder":186},[162,489,490],{"class":164,"line":244},[162,491,448],{},[162,493,494],{"class":164,"line":250},[162,495,496],{},"def constrained_financial_record(draw: st.DrawFn) -> dict:\n",[162,498,499],{"class":164,"line":256},[162,500,501],{}," \"\"\"Generates correlated transaction data with valid currency\u002Famount pairs.\"\"\"\n",[162,503,504],{"class":164,"line":262},[162,505,506],{}," currency = draw(st.sampled_from([\"USD\", \"EUR\", \"GBP\"]))\n",[162,508,509],{"class":164,"line":268},[162,510,511],{}," # Amount precision matches currency decimal places\n",[162,513,514],{"class":164,"line":274},[162,515,516],{}," if currency == \"JPY\":\n",[162,518,519],{"class":164,"line":279},[162,520,521],{}," amount = draw(st.integers(min_value=0, max_value=1_000_000))\n",[162,523,524],{"class":164,"line":285},[162,525,241],{},[162,527,528],{"class":164,"line":291},[162,529,530],{}," amount = draw(st.floats(min_value=0.01, max_value=100_000.00, allow_nan=False))\n",[162,532,533],{"class":164,"line":297},[162,534,535],{}," return {\n",[162,537,538],{"class":164,"line":303},[162,539,540],{}," \"currency\": currency,\n",[162,542,543],{"class":164,"line":309},[162,544,545],{}," \"amount\": round(amount, 4),\n",[162,547,548],{"class":164,"line":315},[162,549,550],{}," \"timestamp\": draw(valid_iso_timestamps()),\n",[162,552,553],{"class":164,"line":321},[162,554,555],{}," \"id\": draw(st.uuids())\n",[162,557,558],{"class":164,"line":327},[162,559,560],{}," }\n",[162,562,563],{"class":164,"line":333},[162,564,187],{"emptyLinePlaceholder":186},[162,566,567],{"class":164,"line":338},[162,568,569],{},"@given(record=constrained_financial_record())\n",[162,571,572],{"class":164,"line":344},[162,573,574],{},"@settings(max_examples=500)\n",[162,576,577],{"class":164,"line":350},[162,578,579],{},"def test_financial_record_serialization(record: dict):\n",[162,581,582],{"class":164,"line":355},[162,583,584],{}," # Validate domain invariants\n",[162,586,587],{"class":164,"line":361},[162,588,589],{}," assert record[\"currency\"] in {\"USD\", \"EUR\", \"GBP\", \"JPY\"}\n",[162,591,592],{"class":164,"line":367},[162,593,594],{}," assert record[\"amount\"] >= 0.0\n",[162,596,597],{"class":164,"line":372},[162,598,599],{}," assert isinstance(record[\"id\"], str)\n",[14,601,602,603,415,606,609,610,612,613,616,617,619,620,622],{},"A critical trade-off exists between ",[32,604,605],{},"assume()",[32,607,608],{},".filter()",". Both reject invalid inputs, but ",[32,611,608],{}," operates at the strategy level, potentially causing ",[32,614,615],{},"Unsatisfiable"," errors if constraints are too tight. ",[32,618,605],{}," operates at the test level, allowing Hypothesis to skip invalid cases gracefully. Over-constraining strategies leads to shallow coverage and generation timeouts. Engineers should prefer ",[32,621,605],{}," for conditional logic and design strategies that generate valid data natively rather than filtering post-generation.",[14,624,625,626,629,630,390],{},"Cross-property dependency modeling requires careful orchestration. When multiple properties interact (e.g., state transitions affecting resource limits), engineers should use ",[32,627,628],{},"st.shared()"," to ensure consistent references across generated inputs. For comprehensive coverage of composite strategies and constraint optimization, refer to ",[386,631,633],{"href":632},"\u002Fproperty-based-fuzz-testing-strategies\u002Fadvanced-property-based-testing\u002F","Advanced Property-Based Testing",[21,635,637],{"id":636},"stateful-testing-for-complex-systems","Stateful Testing for Complex Systems",[14,639,640,641,644],{},"Stateless property tests excel at validating pure functions, but modern applications are inherently stateful. APIs, databases, and message brokers maintain mutable state across sequential operations. Hypothesis addresses this via ",[32,642,643],{},"RuleBasedStateMachine",", which models systems as finite state machines with explicit transitions, preconditions, and invariants.",[14,646,647,648,651],{},"A stateful test defines a set of rules (operations) that can be applied to a system instance. Hypothesis generates sequences of rule applications, exploring valid and invalid transition paths. After each step, ",[32,649,650],{},"@invariant()"," decorators validate system-wide guarantees. This approach automatically discovers race conditions, resource leaks, and invalid state transitions that sequential unit tests miss.",[14,653,654,655,658],{},"Pre\u002Fpost-condition modeling is critical. Rules should declare ",[32,656,657],{},"precondition=lambda self: self.is_connected"," to prevent invalid operations. Post-conditions are enforced via invariants or explicit assertions within the rule body. Teardown validation ensures resources are properly released, catching file descriptor leaks, unclosed connections, and dangling locks.",[14,660,661,662,113,665,113,668,113,671,674,675,113,678,681,682,685],{},"Mapping real-world API workflows to state machines requires identifying core entities and their lifecycle transitions. For example, a user management API might have states: ",[32,663,664],{},"created",[32,666,667],{},"activated",[32,669,670],{},"suspended",[32,672,673],{},"deleted",". Rules map to HTTP endpoints (",[32,676,677],{},"POST \u002Fusers",[32,679,680],{},"PATCH \u002Fusers\u002F{id}\u002Fsuspend","), while invariants enforce business logic (",[32,683,684],{},"assert len(active_users) \u003C= MAX_CONCURRENT",").",[153,687,689],{"className":155,"code":688,"language":157,"meta":158,"style":158},"from hypothesis.stateful import RuleBasedStateMachine, rule, invariant, precondition\nfrom hypothesis import strategies as st, settings\n\nclass MockDatabase:\n def __init__(self):\n self._data: dict[str, dict] = {}\n self._active_count = 0\n\n def create_user(self, user_id: str, role: str) -> bool:\n if user_id in self._data:\n return False\n self._data[user_id] = {\"role\": role, \"active\": True}\n self._active_count += 1\n return True\n\n def deactivate_user(self, user_id: str) -> bool:\n if user_id not in self._data or not self._data[user_id][\"active\"]:\n return False\n self._data[user_id][\"active\"] = False\n self._active_count -= 1\n return True\n\nclass UserManagementStateMachine(RuleBasedStateMachine):\n def __init__(self):\n super().__init__()\n self.db = MockDatabase()\n self._user_ids = []\n\n @rule(user_id=st.text(min_size=1, max_size=10), role=st.sampled_from([\"admin\", \"user\"]))\n def create_user(self, user_id: str, role: str):\n self.db.create_user(user_id, role)\n self._user_ids.append(user_id)\n\n @rule(user_id=st.sampled_from(lambda self: self._user_ids))\n def deactivate_user(self, user_id: str):\n self.db.deactivate_user(user_id)\n\n @precondition(lambda self: len(self._user_ids) > 0)\n @rule()\n def cleanup(self):\n self._user_ids.clear()\n\n @invariant()\n def check_active_count(self):\n actual_active = sum(1 for u in self.db._data.values() if u[\"active\"])\n assert self.db._active_count == actual_active\n\n @invariant()\n def check_no_duplicate_users(self):\n assert len(self.db._data) == len(set(self.db._data.keys()))\n\nTestUserManagement = UserManagementStateMachine.TestCase\n",[32,690,691,696,701,705,710,715,720,725,729,734,739,744,749,754,759,763,768,773,777,782,787,791,795,800,804,809,814,819,823,828,833,838,843,847,852,857,862,866,872,878,884,890,895,901,907,913,919,924,929,935,941,946],{"__ignoreMap":158},[162,692,693],{"class":164,"line":165},[162,694,695],{},"from hypothesis.stateful import RuleBasedStateMachine, rule, invariant, precondition\n",[162,697,698],{"class":164,"line":171},[162,699,700],{},"from hypothesis import strategies as st, settings\n",[162,702,703],{"class":164,"line":177},[162,704,187],{"emptyLinePlaceholder":186},[162,706,707],{"class":164,"line":183},[162,708,709],{},"class MockDatabase:\n",[162,711,712],{"class":164,"line":190},[162,713,714],{}," def __init__(self):\n",[162,716,717],{"class":164,"line":196},[162,718,719],{}," self._data: dict[str, dict] = {}\n",[162,721,722],{"class":164,"line":202},[162,723,724],{}," self._active_count = 0\n",[162,726,727],{"class":164,"line":208},[162,728,187],{"emptyLinePlaceholder":186},[162,730,731],{"class":164,"line":214},[162,732,733],{}," def create_user(self, user_id: str, role: str) -> bool:\n",[162,735,736],{"class":164,"line":220},[162,737,738],{}," if user_id in self._data:\n",[162,740,741],{"class":164,"line":226},[162,742,743],{}," return False\n",[162,745,746],{"class":164,"line":232},[162,747,748],{}," self._data[user_id] = {\"role\": role, \"active\": True}\n",[162,750,751],{"class":164,"line":238},[162,752,753],{}," self._active_count += 1\n",[162,755,756],{"class":164,"line":244},[162,757,758],{}," return True\n",[162,760,761],{"class":164,"line":250},[162,762,187],{"emptyLinePlaceholder":186},[162,764,765],{"class":164,"line":256},[162,766,767],{}," def deactivate_user(self, user_id: str) -> bool:\n",[162,769,770],{"class":164,"line":262},[162,771,772],{}," if user_id not in self._data or not self._data[user_id][\"active\"]:\n",[162,774,775],{"class":164,"line":268},[162,776,743],{},[162,778,779],{"class":164,"line":274},[162,780,781],{}," self._data[user_id][\"active\"] = False\n",[162,783,784],{"class":164,"line":279},[162,785,786],{}," self._active_count -= 1\n",[162,788,789],{"class":164,"line":285},[162,790,758],{},[162,792,793],{"class":164,"line":291},[162,794,187],{"emptyLinePlaceholder":186},[162,796,797],{"class":164,"line":297},[162,798,799],{},"class UserManagementStateMachine(RuleBasedStateMachine):\n",[162,801,802],{"class":164,"line":303},[162,803,714],{},[162,805,806],{"class":164,"line":309},[162,807,808],{}," super().__init__()\n",[162,810,811],{"class":164,"line":315},[162,812,813],{}," self.db = MockDatabase()\n",[162,815,816],{"class":164,"line":321},[162,817,818],{}," self._user_ids = []\n",[162,820,821],{"class":164,"line":327},[162,822,187],{"emptyLinePlaceholder":186},[162,824,825],{"class":164,"line":333},[162,826,827],{}," @rule(user_id=st.text(min_size=1, max_size=10), role=st.sampled_from([\"admin\", \"user\"]))\n",[162,829,830],{"class":164,"line":338},[162,831,832],{}," def create_user(self, user_id: str, role: str):\n",[162,834,835],{"class":164,"line":344},[162,836,837],{}," self.db.create_user(user_id, role)\n",[162,839,840],{"class":164,"line":350},[162,841,842],{}," self._user_ids.append(user_id)\n",[162,844,845],{"class":164,"line":355},[162,846,187],{"emptyLinePlaceholder":186},[162,848,849],{"class":164,"line":361},[162,850,851],{}," @rule(user_id=st.sampled_from(lambda self: self._user_ids))\n",[162,853,854],{"class":164,"line":367},[162,855,856],{}," def deactivate_user(self, user_id: str):\n",[162,858,859],{"class":164,"line":372},[162,860,861],{}," self.db.deactivate_user(user_id)\n",[162,863,864],{"class":164,"line":378},[162,865,187],{"emptyLinePlaceholder":186},[162,867,869],{"class":164,"line":868},38,[162,870,871],{}," @precondition(lambda self: len(self._user_ids) > 0)\n",[162,873,875],{"class":164,"line":874},39,[162,876,877],{}," @rule()\n",[162,879,881],{"class":164,"line":880},40,[162,882,883],{}," def cleanup(self):\n",[162,885,887],{"class":164,"line":886},41,[162,888,889],{}," self._user_ids.clear()\n",[162,891,893],{"class":164,"line":892},42,[162,894,187],{"emptyLinePlaceholder":186},[162,896,898],{"class":164,"line":897},43,[162,899,900],{}," @invariant()\n",[162,902,904],{"class":164,"line":903},44,[162,905,906],{}," def check_active_count(self):\n",[162,908,910],{"class":164,"line":909},45,[162,911,912],{}," actual_active = sum(1 for u in self.db._data.values() if u[\"active\"])\n",[162,914,916],{"class":164,"line":915},46,[162,917,918],{}," assert self.db._active_count == actual_active\n",[162,920,922],{"class":164,"line":921},47,[162,923,187],{"emptyLinePlaceholder":186},[162,925,927],{"class":164,"line":926},48,[162,928,900],{},[162,930,932],{"class":164,"line":931},49,[162,933,934],{}," def check_no_duplicate_users(self):\n",[162,936,938],{"class":164,"line":937},50,[162,939,940],{}," assert len(self.db._data) == len(set(self.db._data.keys()))\n",[162,942,944],{"class":164,"line":943},51,[162,945,187],{"emptyLinePlaceholder":186},[162,947,949],{"class":164,"line":948},52,[162,950,951],{},"TestUserManagement = UserManagementStateMachine.TestCase\n",[14,953,954,955,958,959,961,962,965],{},"Stateful testing requires careful teardown design. Long-running machines can accumulate state, masking resource exhaustion bugs. Implementing explicit ",[32,956,957],{},"@rule()"," cleanup steps and leveraging ",[32,960,105],{},"'s ",[32,963,964],{},"teardown"," fixtures ensures deterministic resource release. For architectural patterns and invariant enforcement strategies, explore Stateful Testing with Hypothesis.",[21,967,969],{"id":968},"fuzz-testing-integration-coverage-optimization","Fuzz Testing Integration & Coverage Optimization",[14,971,972],{},"While property-based testing validates logical invariants using structured data generation, fuzz testing targets low-level crash boundaries, memory safety, and exception handling through byte-level mutation. In Python, the choice between Hypothesis and coverage-guided fuzzers like Atheris depends on the testing target.",[14,974,975],{},"Hypothesis operates at the application layer, generating semantically valid inputs that exercise business logic. Atheris, built atop LLVM's libFuzzer, operates at the interpreter\u002Fextension layer, mutating raw byte streams to trigger segmentation faults, buffer overflows, and unhandled exceptions in C-extensions, parsers, and cryptographic libraries.",[14,977,978,979,982,983,986],{},"Coverage-guided mutation drives modern fuzzing. The fuzzer instruments the target code, tracking executed basic blocks and branch edges. Inputs that increase code coverage are added to a persistent corpus and mutated further. This feedback loop rapidly explores deep code paths that random generation misses. In Python, ",[32,980,981],{},"coverage.py"," or ",[32,984,985],{},"sys.settrace"," can provide branch-level instrumentation, though performance overhead requires careful tuning.",[14,988,989,990,993,994,997,998,113,1001,1004,1005,1008],{},"Handling non-deterministic boundaries is a primary engineering challenge. Fuzzers must isolate time-dependent functions, network I\u002FO, and random number generators. Mocking ",[32,991,992],{},"time.time()",", injecting deterministic seeds, and using ",[32,995,996],{},"unittest.mock"," to patch external dependencies ensures reproducible mutation cycles. Memory safety testing focuses on catching ",[32,999,1000],{},"MemoryError",[32,1002,1003],{},"OverflowError",", and ",[32,1006,1007],{},"RecursionError"," before they propagate to the OS. Exception boundary testing validates that parsers and deserializers fail gracefully rather than corrupting interpreter state.",[14,1010,1011],{},"For high-level Python services, combine Hypothesis for invariant validation with targeted Atheris fuzzing for binary protocol handlers. This hybrid approach maximizes fault detection across the entire stack.",[21,1013,1015],{"id":1014},"production-ready-cicd-pipelines","Production-Ready CI\u002FCD Pipelines",[14,1017,1018],{},"Integrating property and fuzz tests into CI\u002FCD requires addressing reproducibility, performance, and failure triage. Unlike deterministic unit tests, PBT and fuzzing introduce statistical variance that can destabilize pipelines if not properly configured.",[14,1020,1021,1022,1024],{},"Database caching for corpus persistence is non-negotiable. Hypothesis stores discovered edge cases in ",[32,1023,137],{},". CI runners must cache this directory across runs to prevent regression and accelerate test execution. GitHub Actions and GitLab CI provide native caching mechanisms that map to this path.",[14,1026,1027,1028,1031,1032,1035],{},"Timeout management prevents flaky pipeline failures. Property tests can stall when shrinking complex structures or exploring deep state machines. Configure ",[32,1029,1030],{},"@settings(deadline=timedelta(seconds=2), max_examples=100)"," to enforce strict execution bounds. Use ",[32,1033,1034],{},"pytest-timeout"," as a fallback for runaway processes.",[14,1037,1038,1039,1042,1043,1046,1047,1050,1051,1054],{},"Profile tuning via ",[32,1040,1041],{},"HYPOTHESIS_PROFILE"," allows environment-specific configuration. The ",[32,1044,1045],{},"dev"," profile prioritizes fast feedback with fewer examples, while the ",[32,1048,1049],{},"ci"," profile maximizes coverage with extended runs and strict deadlines. Statistical reporting via ",[32,1052,1053],{},"--hypothesis-show-statistics"," provides visibility into generation efficiency, shrink success rates, and corpus growth. Automated failure triage scripts can parse Hypothesis output, categorize failures by strategy, and generate actionable bug reports.",[153,1056,1060],{"className":1057,"code":1058,"language":1059,"meta":158,"style":158},"language-yaml shiki shiki-themes github-light github-dark","# .github\u002Fworkflows\u002Ftest.yml\nname: Property & Fuzz Tests\non: [push, pull_request]\n\njobs:\n test:\n runs-on: ubuntu-latest\n env:\n HYPOTHESIS_PROFILE: ci\n PYTHONDONTWRITEBYTECODE: 1\n steps:\n - uses: actions\u002Fcheckout@v4\n - uses: actions\u002Fsetup-python@v5\n with:\n python-version: \"3.11\"\n - name: Cache Hypothesis Database\n uses: actions\u002Fcache@v3\n with:\n path: .hypothesis\n key: hypothesis-db-${{ runner.os }}-${{ hashFiles('**\u002Frequirements.txt') }}\n restore-keys: |\n hypothesis-db-${{ runner.os }}-\n - name: Install Dependencies\n run: pip install -r requirements.txt pytest hypothesis pytest-xdist\n - name: Run Property & Fuzz Tests\n run: |\n pytest tests\u002F \\\n --hypothesis-show-statistics \\\n --timeout=300 \\\n --numprocesses=auto \\\n -v\n - name: Upload Fuzz Corpus\n if: always()\n uses: actions\u002Fupload-artifact@v4\n with:\n name: hypothesis-corpus\n path: .hypothesis\u002Fexamples\u002F\n","yaml",[32,1061,1062,1068,1082,1102,1106,1114,1121,1131,1138,1148,1158,1165,1178,1189,1196,1206,1217,1227,1233,1243,1253,1264,1269,1274,1279,1284,1289,1294,1299,1304,1309,1314,1319,1324,1329,1334,1339],{"__ignoreMap":158},[162,1063,1064],{"class":164,"line":165},[162,1065,1067],{"class":1066},"sJ8bj","# .github\u002Fworkflows\u002Ftest.yml\n",[162,1069,1070,1074,1078],{"class":164,"line":171},[162,1071,1073],{"class":1072},"s9eBZ","name",[162,1075,1077],{"class":1076},"sVt8B",": ",[162,1079,1081],{"class":1080},"sZZnC","Property & Fuzz Tests\n",[162,1083,1084,1088,1091,1094,1096,1099],{"class":164,"line":177},[162,1085,1087],{"class":1086},"sj4cs","on",[162,1089,1090],{"class":1076},": [",[162,1092,1093],{"class":1080},"push",[162,1095,113],{"class":1076},[162,1097,1098],{"class":1080},"pull_request",[162,1100,1101],{"class":1076},"]\n",[162,1103,1104],{"class":164,"line":183},[162,1105,187],{"emptyLinePlaceholder":186},[162,1107,1108,1111],{"class":164,"line":190},[162,1109,1110],{"class":1072},"jobs",[162,1112,1113],{"class":1076},":\n",[162,1115,1116,1119],{"class":164,"line":196},[162,1117,1118],{"class":1072}," test",[162,1120,1113],{"class":1076},[162,1122,1123,1126,1128],{"class":164,"line":202},[162,1124,1125],{"class":1072}," runs-on",[162,1127,1077],{"class":1076},[162,1129,1130],{"class":1080},"ubuntu-latest\n",[162,1132,1133,1136],{"class":164,"line":208},[162,1134,1135],{"class":1072}," env",[162,1137,1113],{"class":1076},[162,1139,1140,1143,1145],{"class":164,"line":214},[162,1141,1142],{"class":1072}," HYPOTHESIS_PROFILE",[162,1144,1077],{"class":1076},[162,1146,1147],{"class":1080},"ci\n",[162,1149,1150,1153,1155],{"class":164,"line":220},[162,1151,1152],{"class":1072}," PYTHONDONTWRITEBYTECODE",[162,1154,1077],{"class":1076},[162,1156,1157],{"class":1086},"1\n",[162,1159,1160,1163],{"class":164,"line":226},[162,1161,1162],{"class":1072}," steps",[162,1164,1113],{"class":1076},[162,1166,1167,1170,1173,1175],{"class":164,"line":232},[162,1168,1169],{"class":1076}," - ",[162,1171,1172],{"class":1072},"uses",[162,1174,1077],{"class":1076},[162,1176,1177],{"class":1080},"actions\u002Fcheckout@v4\n",[162,1179,1180,1182,1184,1186],{"class":164,"line":238},[162,1181,1169],{"class":1076},[162,1183,1172],{"class":1072},[162,1185,1077],{"class":1076},[162,1187,1188],{"class":1080},"actions\u002Fsetup-python@v5\n",[162,1190,1191,1194],{"class":164,"line":244},[162,1192,1193],{"class":1072}," with",[162,1195,1113],{"class":1076},[162,1197,1198,1201,1203],{"class":164,"line":250},[162,1199,1200],{"class":1072}," python-version",[162,1202,1077],{"class":1076},[162,1204,1205],{"class":1080},"\"3.11\"\n",[162,1207,1208,1210,1212,1214],{"class":164,"line":256},[162,1209,1169],{"class":1076},[162,1211,1073],{"class":1072},[162,1213,1077],{"class":1076},[162,1215,1216],{"class":1080},"Cache Hypothesis Database\n",[162,1218,1219,1222,1224],{"class":164,"line":262},[162,1220,1221],{"class":1072}," uses",[162,1223,1077],{"class":1076},[162,1225,1226],{"class":1080},"actions\u002Fcache@v3\n",[162,1228,1229,1231],{"class":164,"line":268},[162,1230,1193],{"class":1072},[162,1232,1113],{"class":1076},[162,1234,1235,1238,1240],{"class":164,"line":274},[162,1236,1237],{"class":1072}," path",[162,1239,1077],{"class":1076},[162,1241,1242],{"class":1080},".hypothesis\n",[162,1244,1245,1248,1250],{"class":164,"line":279},[162,1246,1247],{"class":1072}," key",[162,1249,1077],{"class":1076},[162,1251,1252],{"class":1080},"hypothesis-db-${{ runner.os }}-${{ hashFiles('**\u002Frequirements.txt') }}\n",[162,1254,1255,1258,1260],{"class":164,"line":285},[162,1256,1257],{"class":1072}," restore-keys",[162,1259,1077],{"class":1076},[162,1261,1263],{"class":1262},"szBVR","|\n",[162,1265,1266],{"class":164,"line":291},[162,1267,1268],{"class":1080}," hypothesis-db-${{ runner.os }}-\n",[162,1270,1271],{"class":164,"line":297},[162,1272,1273],{"class":1080}," - name: Install Dependencies\n",[162,1275,1276],{"class":164,"line":303},[162,1277,1278],{"class":1080}," run: pip install -r requirements.txt pytest hypothesis pytest-xdist\n",[162,1280,1281],{"class":164,"line":309},[162,1282,1283],{"class":1080}," - name: Run Property & Fuzz Tests\n",[162,1285,1286],{"class":164,"line":315},[162,1287,1288],{"class":1080}," run: |\n",[162,1290,1291],{"class":164,"line":321},[162,1292,1293],{"class":1080}," pytest tests\u002F \\\n",[162,1295,1296],{"class":164,"line":327},[162,1297,1298],{"class":1080}," --hypothesis-show-statistics \\\n",[162,1300,1301],{"class":164,"line":333},[162,1302,1303],{"class":1080}," --timeout=300 \\\n",[162,1305,1306],{"class":164,"line":338},[162,1307,1308],{"class":1080}," --numprocesses=auto \\\n",[162,1310,1311],{"class":164,"line":344},[162,1312,1313],{"class":1080}," -v\n",[162,1315,1316],{"class":164,"line":350},[162,1317,1318],{"class":1080}," - name: Upload Fuzz Corpus\n",[162,1320,1321],{"class":164,"line":355},[162,1322,1323],{"class":1080}," if: always()\n",[162,1325,1326],{"class":164,"line":361},[162,1327,1328],{"class":1080}," uses: actions\u002Fupload-artifact@v4\n",[162,1330,1331],{"class":164,"line":367},[162,1332,1333],{"class":1080}," with:\n",[162,1335,1336],{"class":164,"line":372},[162,1337,1338],{"class":1080}," name: hypothesis-corpus\n",[162,1340,1341],{"class":164,"line":378},[162,1342,1343],{"class":1080}," path: .hypothesis\u002Fexamples\u002F\n",[14,1345,1346],{},"For comprehensive CI configuration, timeout tuning, and automated triage workflows, review Integrating Fuzz Tests into CI.",[21,1348,1350],{"id":1349},"performance-profiling-test-optimization","Performance Profiling & Test Optimization",[14,1352,1353],{},"As test suites scale, generation overhead and shrinking latency can become CI bottlenecks. Profiling and optimization require a systematic approach to strategy design, parallelization, and resource management.",[14,1355,1356,1359,1360,1363,1364,1367],{},[32,1357,1358],{},"pytest-xdist"," enables parallel execution across multiple workers, but Hypothesis's internal database requires careful isolation. Each worker must maintain an independent ",[32,1361,1362],{},".hypothesis"," directory or use file locking to prevent corruption. Configure ",[32,1365,1366],{},"--dist=loadfile"," to group related tests and minimize database contention.",[14,1369,1370,1373,1374,1377,1378,1380,1381,1383],{},[32,1371,1372],{},"cProfile"," integration identifies slow generation paths. Wrapping test execution with ",[32,1375,1376],{},"python -m cProfile -o profile.stats -m pytest"," reveals bottlenecks in strategy composition or shrinking logic. Common culprits include deeply nested ",[32,1379,414],{}," functions, excessive ",[32,1382,608],{}," calls, and unbounded recursive strategies. Refactor these into iterative generators or pre-computed lookup tables.",[14,1385,1386,1387,1390,1391,1394,1395,1398],{},"Memory leak detection is critical for long-running fuzz sessions. Python's ",[32,1388,1389],{},"tracemalloc"," module tracks object allocation over time. Enable it in CI to detect unclosed file handles, lingering mock objects, or circular references in generated data structures. Set ",[32,1392,1393],{},"tracemalloc.start()"," in ",[32,1396,1397],{},"conftest.py"," and assert that peak memory usage remains within acceptable thresholds.",[14,1400,1401,1402,1405],{},"Corpus pruning and deduplication prevent database bloat. Hypothesis automatically deduplicates examples, but engineers should periodically run ",[32,1403,1404],{},"hypothesis clean"," or implement custom pruning scripts that remove obsolete examples after major refactors. This maintains fast startup times and prevents CI cache bloat.",[1407,1408,1410],"h3",{"id":1409},"common-pitfalls-anti-patterns","Common Pitfalls & Anti-Patterns",[1412,1413,1414,1429,1439,1445,1454,1463],"ol",{},[51,1415,1416,1422,1423,1425,1426,1428],{},[54,1417,1418,1419,1421],{},"Over-constraining with ",[32,1420,608],{},":"," Leads to shallow coverage and ",[32,1424,615],{}," errors. Prefer ",[32,1427,605],{}," or design strategies that generate valid data natively.",[51,1430,1431,1434,1435,1438],{},[54,1432,1433],{},"Ignoring shrinking performance:"," Complex custom strategies without optimized ",[32,1436,1437],{},"__repr__"," or shrink paths cause CI timeouts. Implement explicit shrink logic for composite types.",[51,1440,1441,1444],{},[54,1442,1443],{},"Mixing side-effects with pure properties:"," Network calls, database writes, or global state mutations during generation break reproducibility. Isolate I\u002FO via dependency injection or mocking.",[51,1446,1447,1450,1451,1453],{},[54,1448,1449],{},"Failing to persist corpora:"," Losing ",[32,1452,137],{}," across CI runs discards discovered edge cases. Always cache the database directory.",[51,1455,1456,1462],{},[54,1457,1458,1459,1421],{},"Relying solely on ",[32,1460,1461],{},"@assume()"," Without fallback generation, assume-heavy tests waste cycles skipping invalid inputs. Balance assumptions with constrained strategy design.",[51,1464,1465,1468],{},[54,1466,1467],{},"Using PBT for happy-path validation:"," Property tests excel at boundary exploration, not deterministic workflow verification. Reserve example-based tests for critical business paths.",[21,1470,1472],{"id":1471},"frequently-asked-questions","Frequently Asked Questions",[14,1474,1475,1478],{},[54,1476,1477],{},"When should I use property-based testing instead of traditional unit tests?","\nUse PBT for boundary validation, invariant checking, and edge-case discovery where combinatorial input spaces make exhaustive example coverage impractical. Reserve traditional unit tests for deterministic happy-path verification, critical business logic anchoring, and regression testing of known bugs. The two approaches are complementary: unit tests verify specific contracts, while PBT verifies systemic guarantees.",[14,1480,1481,1484],{},[54,1482,1483],{},"How does Hypothesis handle non-deterministic code?","\nHypothesis isolates non-determinism through explicit seed control, mock injection, and strategy isolation. Time-dependent functions should be patched or passed as parameters. Network I\u002FO must be mocked or replaced with deterministic stubs. By controlling the random number generator and caching generated inputs, Hypothesis ensures that test execution remains fully reproducible across environments and CI runs.",[14,1486,1487,1490],{},[54,1488,1489],{},"What is the difference between property-based testing and fuzzing in Python?","\nProperty testing validates logical invariants using structured, type-aware generation. It focuses on high-level business rules and algebraic properties. Fuzzing targets memory safety, crash boundaries, and exception handling through byte-level mutation and coverage-guided exploration. PBT is ideal for application logic; fuzzing is optimal for parsers, C-extensions, and protocol handlers. Modern pipelines often combine both for comprehensive fault detection.",[14,1492,1493,1496,1497,1500,1501,1503,1504,1506,1507,415,1510,1513,1514,1516],{},[54,1494,1495],{},"How do I prevent property tests from slowing down CI pipelines?","\nOptimize CI performance through profile tuning (",[32,1498,1499],{},"HYPOTHESIS_PROFILE=ci","), strict example limits, and parallel execution via ",[32,1502,1358],{},". Cache the ",[32,1505,1362],{}," database to avoid redundant generation. Implement ",[32,1508,1509],{},"deadline",[32,1511,1512],{},"timeout"," settings to prevent runaway shrinking. Use ",[32,1515,1053],{}," to monitor generation efficiency and refactor slow strategies. Finally, prune obsolete examples regularly to maintain fast startup times.",[1518,1519,1520],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":158,"searchDepth":171,"depth":171,"links":1522},[1523,1524,1525,1526,1527,1528,1529,1532],{"id":23,"depth":171,"text":24},{"id":98,"depth":171,"text":99},{"id":393,"depth":171,"text":394},{"id":636,"depth":171,"text":637},{"id":968,"depth":171,"text":969},{"id":1014,"depth":171,"text":1015},{"id":1349,"depth":171,"text":1350,"children":1530},[1531],{"id":1409,"depth":177,"text":1410},{"id":1471,"depth":171,"text":1472},"md",{},"\u002Fproperty-based-fuzz-testing-strategies",{"title":5,"description":16},"property-based-fuzz-testing-strategies\u002Findex","ymph9o_hoWyxV3cDmgaGgM2LRhpxsGribjDFl7Rz0BA",1778004577653]