Property based testing — DedSec Project
Property-based testing — seeded cases plus explicit invariants Subject under test Build a stable deduplication routine: preserve each distinct hashable value once, in the order of its first…
Property-based testing — seeded cases plus explicit invariants
Subject under test
Build a stable deduplication routine: preserve each distinct hashable value once, in the order of its first appearance. A few handwritten examples cannot exercise every sequence length and repetition pattern. Generate many bounded examples with a fixed pseudorandom seed so a failure is reproducible. Compare with an independent standard-library oracle and also assert structural properties that should hold for every input.
Executable Python 3 fixture
Save as property_lab.py and run python3 property_lab.py. The generator produces 100 sequences of up to 39 integers from 0 through 9, so there is no external service or unbounded random work.
import random
def unique(items):
seen, result = set(), []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
return result
rng = random.Random(17)
for _ in range(100):
xs = [rng.randrange(10) for _ in range(rng.randrange(40))]
result = unique(xs)
assert result == list(dict.fromkeys(xs))
assert unique(result) == result
assert set(result) == set(xs)
positions = [xs.index(value) for value in result]
assert positions == sorted(positions)
assert unique([]) == []
print("PASS: seeded properties and order preservation")
What makes a useful property
Idempotence: deduplicating an already deduplicated list changes nothing. Membership preservation: the output contains exactly the set of input values. Order preservation: the first appearance positions must be strictly increasing. These properties do not prove correctness in every case, and the standard-library dict reference may share assumptions with the implementation. Independent specifications and hand-picked edge cases remain necessary. A seed makes the run repeatable, but a real property-based library can also shrink a failing sample into a smaller counterexample.
Bounded experiments
- Intentionally reverse the resulting list and verify which property notices the defect; a mere membership check will miss ordering bugs.
- Include empty input, only repeated values and all-unique values. Record which tests are deterministic.
- Try unhashable list values. Decide whether the contract rejects them or needs an alternative equality-only algorithm.
- Increase the seed count and record the first failing seed for a deliberately mutated implementation. Explain how shrinking helps debugging.
Evidence: PASS, four independently stated properties, a reproducible seed and at least one mutation detected by a property.