Fedezze fel a tulajdonság-alapú tesztelést a Python Hypothesis könyvtárával. Lépjen túl a példateszteken, hogy szélsőértékeket találjon és robusztusabb szoftvert építsen.
Az egységteszteken túl: Mélyreható betekintés a tulajdonság-alapú tesztelésbe a Python Hypothesis könyvtárával
A szoftverfejlesztés világában a tesztelés a minőség alapja. Évtizedek óta a domináns paradigma a példa-alapú tesztelés. Gondosan összeállítjuk a bemeneteket, meghatározzuk a várt kimeneteket, és állításokat írunk annak ellenőrzésére, hogy kódunk a tervek szerint működik-e. Ez a megközelítés, amely olyan keretrendszerekben található meg, mint a unittest és a pytest, hatékony és alapvető. De mi van, ha azt mondanám, hogy létezik egy kiegészítő megközelítés, amely olyan hibákat tárhat fel, amelyekre soha nem is gondoltál volna?
Üdvözöljük a tulajdonság-alapú tesztelés világában, egy olyan paradigmában, amely a fókuszát a specifikus példák teszteléséről a kód általános tulajdonságainak ellenőrzésére helyezi át. És a Python ökoszisztémában ennek a megközelítésnek a vitathatatlan bajnoka egy könyvtár, melynek neve Hypothesis.
Ez az átfogó útmutató elvezeti Önt a teljes kezdő szinttől a tulajdonság-alapú tesztelés magabiztos gyakorlójává a Hypothesis segítségével. Feltárjuk az alapvető koncepciókat, elmerülünk a gyakorlati példákban, és megtanuljuk, hogyan integrálhatja ezt a hatékony eszközt a mindennapi fejlesztési munkafolyamatába, hogy robusztusabb, megbízhatóbb és hibáknak ellenállóbb szoftvert építsen.
Mi az a tulajdonság-alapú tesztelés? Gondolkodásmódváltás
A Hypothesis megértéséhez először meg kell értenünk a tulajdonság-alapú tesztelés alapvető ötletét. Hasonlítsuk össze a hagyományos, példa-alapú teszteléssel, amit mindannyian ismerünk.
Példa-alapú tesztelés: Az ismerős út
Képzelje el, hogy írt egy egyedi rendező függvényt, a my_sort()-ot. Példa-alapú teszteléssel a gondolkodási folyamata a következő lenne:
- "Teszteljük egy egyszerű, rendezett listával." ->
assert my_sort([1, 2, 3]) == [1, 2, 3] - "Mi van egy fordított sorrendű listával?" ->
assert my_sort([3, 2, 1]) == [1, 2, 3] - "Mi a helyzet egy üres listával?" ->
assert my_sort([]) == [] - "Egy lista ismétlődésekkel?" ->
assert my_sort([5, 1, 5, 2]) == [1, 2, 5, 5] - "És egy lista negatív számokkal?" ->
assert my_sort([-1, -5, 0]) == [-5, -1, 0]
Ez hatékony, de van egy alapvető korlátja: csak azokat az eseteket teszteli, amelyekre gondolni tud. A tesztjei csak annyira jók, amennyire a képzelete. Kihagyhat szélsőértékeket, amelyek nagyon nagy számokat, lebegőpontos pontatlanságokat, specifikus Unicode karaktereket vagy összetett adatkombinációkat érintenek, amelyek váratlan viselkedéshez vezetnek.
Tulajdonság-alapú tesztelés: Invariánsokban való gondolkodás
A tulajdonság-alapú tesztelés megfordítja a forgatókönyvet. Ahelyett, hogy specifikus példákat adna meg, Ön definiálja a tulajdonságait, vagy invariánsait, a függvényének – olyan szabályokat, amelyeknek bármely érvényes bemenetre igaznak kell lenniük. A my_sort() függvényünk esetében ezek a tulajdonságok a következők lehetnek:
- A kimenet rendezett: Bármely számlista esetén a kimeneti lista minden eleme kisebb vagy egyenlő az őt követő elemmel.
- A kimenet ugyanazokat az elemeket tartalmazza, mint a bemenet: A rendezett lista csak az eredeti lista permutációja; nincsenek hozzáadott vagy elveszett elemek.
- A függvény idempotens: Egy már rendezett lista rendezése nem változtathatja meg azt. Azaz,
my_sort(my_sort(some_list)) == my_sort(some_list).
Ezzel a megközelítéssel nem a tesztadatokat írja meg. Ön a szabályokat írja meg. Ezután hagyja, hogy egy keretrendszer, például a Hypothesis, több száz vagy ezer véletlenszerű, változatos és gyakran ravasz bemenetet generáljon, hogy megpróbálja bebizonyítani a tulajdonságai téves voltát. Ha talál egy olyan bemenetet, amely megsért egy tulajdonságot, akkor hibát talált.
Bemutatkozik a Hypothesis: Az Ön automatizált tesztadat-generátora
A Hypothesis a vezető tulajdonság-alapú tesztelő könyvtár Pythonhoz. Fogja az Ön által definiált tulajdonságokat, és elvégzi azt a kemény munkát, hogy tesztadatokat generáljon azok kihívására. Ez nem csak egy véletlenszerű adatgenerátor; ez egy intelligens és hatékony eszköz, amelyet a hibák hatékony megtalálására terveztek.
A Hypothesis főbb jellemzői
- Automatikus teszteset-generálás: Ön határozza meg a szükséges adatok *formáját* (pl. "egész számok listája", "csak betűket tartalmazó sztring", "jövőbeli dátum és idő"), és a Hypothesis széles skálájú példákat generál, amelyek megfelelnek ennek a formának.
- Intelligens zsugorítás (Shrinking): Ez a varázslatos funkció. Amikor a Hypothesis hibás tesztesetet talál (pl. egy 50 komplex számból álló lista, amely összeomlasztja a rendező függvényt), nem csak azt a hatalmas listát jelenti. Intelligensen és automatikusan egyszerűsíti a bemenetet, hogy megtalálja a legkisebb lehetséges példát, amely még mindig okozza a hibát. Egy 50 elemből álló lista helyett azt jelentheti, hogy a hiba mindössze
[inf, nan]értékkel fordul elő. Ez hihetetlenül gyorssá és hatékonnyá teszi a hibakeresést. - Zökkenőmentes integráció: A Hypothesis tökéletesen integrálódik olyan népszerű tesztelő keretrendszerekkel, mint a
pytestés azunittest. Tulajdonság-alapú teszteket adhat hozzá meglévő példa-alapú tesztjei mellé anélkül, hogy megváltoztatná a munkafolyamatát. - Stratégiák gazdag könyvtára: Beépített "stratégiák" hatalmas gyűjteményével rendelkezik, amelyek mindent generálnak, az egyszerű egész számoktól és sztringektől kezdve a komplex, beágyazott adatstruktúrákig, időzóna-tudatos dátum- és időpontokig, sőt még NumPy tömbökig is.
- Állapot-alapú tesztelés (Stateful Testing): Összetettebb rendszerek esetén a Hypothesis képes műveletek sorozatát tesztelni, hogy hibákat találjon az állapotátmenetekben, ami példa-alapú teszteléssel köztudottan nehéz.
Kezdő lépések: Az első Hypothesis tesztje
Lássunk hozzá a gyakorlati részhez. A Hypothesis megértésének legjobb módja, ha működés közben látjuk.
Telepítés
Először telepítenie kell a Hypothesist és az Ön által választott tesztfuttatót (mi a pytest-et fogjuk használni). Ez olyan egyszerű, mint:
pip install pytest hypothesis
Egy egyszerű példa: Egy abszolútérték-függvény
Nézzünk egy egyszerű függvényt, amelynek egy szám abszolút értékét kellene kiszámítania. Egy kissé hibás implementáció így nézhet ki:
# a `my_math.py` nevű fájlban
def custom_abs(x):
"""Az abszolút érték függvény egyedi implementációja."""
if x < 0:
return -x
return x
Most írjunk egy tesztfájlt, a test_my_math.py-t. Először a hagyományos pytest megközelítés:
# test_my_math.py (Példa-alapú)
def test_abs_positive():
assert custom_abs(5) == 5
def test_abs_negative():
assert custom_abs(-5) == 5
def test_abs_zero():
assert custom_abs(0) == 0
Ezek a tesztek átmennek. A függvényünk helyesnek tűnik ezen példák alapján. De most írjunk egy tulajdonság-alapú tesztet a Hypothesis segítségével. Mi az abszolút érték függvény alapvető tulajdonsága? Az eredmény soha nem lehet negatív.
# test_my_math.py (Tulajdonság-alapú Hypothesis-szel)
from hypothesis import given
from hypothesis import strategies as st
from my_math import custom_abs
@given(st.integers())
def test_abs_property_is_non_negative(x):
"""Tulajdonság: Bármely egész szám abszolút értéke mindig >= 0."""
assert custom_abs(x) >= 0
Nézzük meg részletesebben:
from hypothesis import given, strategies as st: Importáljuk a szükséges komponenseket. Agivenegy dekorátor, amely egy hagyományos tesztfüggvényt tulajdonság-alapú tesztté alakít. Astrategiesaz a modul, ahol az adatgenerátorainkat találjuk.@given(st.integers()): Ez a teszt magja. A@givendekorátor azt mondja a Hypothesisnek, hogy többször futtassa le ezt a tesztfüggvényt. Minden futtatásnál generál egy értéket a megadott stratégia, azst.integers()segítségével, és átadja aztxargumentumként a tesztfüggvényünknek.assert custom_abs(x) >= 0: Ez a tulajdonságunk. Azt állítjuk, hogy bármelyxegész számra, amit a Hypothesis kitalál, a függvényünk eredményének nagyobbnak vagy egyenlőnek kell lennie nullával.
Amikor ezt futtatja a pytest-tel, valószínűleg sok értékre át fog menni. A Hypothesis megpróbálja a 0-t, -1-et, 1-et, nagy pozitív számokat, nagy negatív számokat és még sok mást. Egyszerű függvényünk mindezeket helyesen kezeli. Most próbáljunk ki egy másik stratégiát, hogy lássuk, találunk-e gyengeséget.
# Teszteljük lebegőpontos számokkal
@given(st.floats())
def test_abs_floats_property(x):
assert custom_abs(x) >= 0
Ha ezt futtatja, a Hypothesis gyorsan talál egy hibás esetet!
Falsifying example: test_abs_floats_property(x=nan) ... assert custom_abs(nan) >= 0 AssertionError: assert nan >= 0
A Hypothesis felfedezte, hogy függvényünk, amikor float('nan') (Not a Number) értéket kap, nan-t ad vissza. A nan >= 0 állítás hamis. Épp most találtunk egy finom hibát, amelyre valószínűleg nem gondoltunk volna manuális tesztelés során. Javíthatnánk a függvényünket, hogy kezelje ezt az esetet, például egy ValueError kiváltásával vagy egy specifikus érték visszaadásával.
Még jobb, mi van, ha a hiba egy nagyon specifikus lebegőpontos számmal volt? A Hypothesis zsugorítója egy nagy, komplex, hibás számot a legegyszerűbb lehetséges verzióra redukált volna, ami még mindig kiváltja a hibát.
A stratégiák ereje: Tesztadatok készítése
A stratégiák a Hypothesis szíve. Ezek adatok generálására szolgáló receptek. A könyvtár beépített stratégiák széles skáláját tartalmazza, és ezeket kombinálva és testreszabva gyakorlatilag bármilyen elképzelhető adatstruktúrát generálhat.
Gyakori beépített stratégiák
- Numerikus:
st.integers(min_value=0, max_value=1000): Egész számokat generál, opcionálisan meghatározott tartományon belül.st.floats(min_value=0.0, max_value=1.0, allow_nan=False, allow_infinity=False): Lebegőpontos számokat generál, speciális értékek finomhangolt szabályozásával.st.fractions(),st.decimals()
- Szöveg:
st.text(min_size=1, max_size=50): Meghatározott hosszúságú Unicode sztringeket generál.st.text(alphabet='abcdef0123456789'): Sztringeket generál egy adott karakterkészletből (pl. hexadecimális kódokhoz).st.characters(): Egyedi karaktereket generál.
- Gyűjtemények:
st.lists(st.integers(), min_size=1): Listákat generál, ahol minden elem egész szám. Figyelje meg, hogyan adunk át egy másik stratégiát argumentumként! Ezt kompozíciónak nevezzük.st.tuples(st.text(), st.booleans()): Rögzített struktúrájú tuple-ket generál.st.sets(st.integers())st.dictionaries(keys=st.text(), values=st.integers()): Szótárakat generál meghatározott kulcs- és értéktípusokkal.
- Időbeli:
st.dates(),st.times(),st.datetimes(),st.timedeltas(). Ezek időzóna-tudatossá tehetők.
- Vegyes:
st.booleans():TruevagyFalseértéket generál.st.just('constant_value'): Mindig ugyanazt az egyetlen értéket generálja. Hasznos komplex stratégiák összeállításához.st.one_of(st.integers(), st.text()): Értéket generál a megadott stratégiák egyikéből.st.none(): CsakNoneértéket generál.
Stratégiák kombinálása és átalakítása
A Hypothesis igazi ereje abban rejlik, hogy képes komplex stratégiákat építeni egyszerűbbekből.
A .map() használata
A .map() metódus lehetővé teszi, hogy egy stratégiából származó értéket átalakítson valami mássá. Ez tökéletes az egyedi osztályainak objektumainak létrehozásához.
# Egy egyszerű adat osztály
from dataclasses import dataclass
@dataclass
class User:
user_id: int
username: str
# Egy stratégia User objektumok generálására
user_strategy = st.builds(
User,
user_id=st.integers(min_value=1),
username=st.text(min_size=3, alphabet='abcdefghijklmnopqrstuvwxyz')
)
@given(user=user_strategy)
def test_user_creation(user):
assert isinstance(user, User)
assert user.user_id > 0
assert user.username.isalpha()
A .filter() és az assume() használata
Néha el kell utasítania bizonyos generált értékeket. Például szükség lehet egy egész számok listájára, ahol az összeg nem nulla. Használhatja a .filter()-t:
st.lists(st.integers()).filter(lambda x: sum(x) != 0)
Azonban a .filter() használata hatékonytalan lehet. Ha a feltétel gyakran hamis, a Hypothesis sok időt tölthet egy érvényes példa generálásával. Gyakran jobb megközelítés az assume() használata a tesztfüggvényen belül:
from hypothesis import assume
@given(st.lists(st.integers()))
def test_something_with_non_zero_sum_list(numbers):
assume(sum(numbers) != 0)
# ... az Ön tesztlogikája itt ...
Az assume() azt mondja a Hypothesisnek: "Ha ez a feltétel nem teljesül, egyszerűen dobja el ezt a példát, és próbáljon ki egy újat." Ez egy közvetlenebb és gyakran hatékonyabb módja a tesztadatok korlátozásának.
Az st.composite() használata
Valóban komplex adatgenerálás esetén, ahol az egyik generált érték a másiktól függ, az st.composite() a szükséges eszköz. Lehetővé teszi, hogy írjon egy függvényt, amely speciális draw függvényt vesz argumentumként, amellyel lépésről lépésre húzhat értékeket más stratégiákból.
Klasszikus példa egy lista és egy érvényes index generálása a listához.
@st.composite
def list_and_index(draw):
# Először húzzon egy nem üres listát
my_list = draw(st.lists(st.integers(), min_size=1))
# Aztán húzzon egy indexet, amely garantáltan érvényes az adott listára
index = draw(st.integers(min_value=0, max_value=len(my_list) - 1))
return (my_list, index)
@given(data=list_and_index())
def test_list_access(data):
my_list, index = data
# Ez a hozzáférés garantáltan biztonságos, mivel így építettük fel a stratégiát
element = my_list[index]
assert element is not None # Egy egyszerű állítás
A Hypothesis működés közben: Valós forgatókönyvek
Alkalmazzuk ezeket a fogalmakat valósághűbb problémákra, amelyekkel a szoftverfejlesztők nap mint nap szembesülnek.
1. forgatókönyv: Adatszerializációs függvény tesztelése
Képzeljen el egy függvényt, amely szerializál egy felhasználói profilt (egy szótárat) egy URL-biztonságos sztringgé, és egy másikat, amely deszerializálja azt. Kulcsfontosságú tulajdonság, hogy a folyamatnak tökéletesen visszafordíthatónak kell lennie.
import json
import base64
def serialize_profile(data: dict) -> str:
"""Szerializál egy szótárat URL-biztonságos base64 sztringgé."""
json_string = json.dumps(data)
return base64.urlsafe_b64encode(json_string.encode('utf-8')).decode('utf-8')
def deserialize_profile(encoded_str: str) -> dict:
"""Deszerializál egy sztringet vissza szótárrá."""
json_string = base64.urlsafe_b64decode(encoded_str.encode('utf-8')).decode('utf-8')
return json.loads(json_string)
# Most a teszthez
# Szükségünk van egy stratégiára, amely JSON-kompatibilis szótárakat generál
json_dictionaries = st.dictionaries(
keys=st.text(),
values=st.recursive(st.none() | st.booleans() | st.floats(allow_nan=False) | st.text(),
lambda children: st.lists(children) | st.dictionaries(st.text(), children),
max_leaves=10)
)
@given(profile=json_dictionaries)
def test_serialization_roundtrip(profile):
"""Tulajdonság: Egy kódolt profil deszerializálása az eredeti profilt kell, hogy visszaadja."""
encoded = serialize_profile(profile)
decoded = deserialize_profile(encoded)
assert profile == decoded
2. forgatókönyv: Rendezési algoritmus tesztelése
Térjünk vissza a rendezési példánkhoz. Így tesztelné a korábban definiált tulajdonságokat.
from collections import Counter
def my_buggy_sort(numbers):
# Vezessünk be egy finom hibát: eldobja az ismétlődéseket
return sorted(list(set(numbers)))
@given(st.lists(st.integers()))
def test_sorting_properties(numbers):
sorted_list = my_buggy_sort(numbers)
# 1. Tulajdonság: A kimenet rendezett
for i in range(len(sorted_list) - 1):
assert sorted_list[i] <= sorted_list[i+1]
# 2. Tulajdonság: Az elemek megegyeznek (ez találja meg a hibát)
assert Counter(numbers) == Counter(sorted_list)
# 3. Tulajdonság: A függvény idempotens
assert my_buggy_sort(sorted_list) == sorted_list
Amikor lefuttatja ezt a tesztet, a Hypothesis gyorsan talál egy hibás példát a 2. tulajdonságra, például numbers=[0, 0]. Függvényünk [0]-t ad vissza, és Counter([0, 0]) nem egyenlő Counter([0])-vel. A zsugorító gondoskodik arról, hogy a hibás példa a lehető legegyszerűbb legyen, azonnal nyilvánvalóvá téve a hiba okát.
3. forgatókönyv: Állapot-alapú tesztelés
Az idővel változó belső állapotú objektumok (például adatbázis-kapcsolat, bevásárlókosár vagy gyorsítótár) esetében hihetetlenül nehéz hibákat találni. Egy hiba kiváltásához egy specifikus műveletsorra lehet szükség. A Hypothesis pontosan erre a célra biztosítja a `RuleBasedStateMachine`-t.
Képzeljen el egy egyszerű API-t egy memórián belüli kulcs-érték tárolóhoz:
class SimpleKeyValueStore:
def __init__(self):
self._data = {}
def set(self, key, value):
self._data[key] = value
def get(self, key):
return self._data.get(key)
def delete(self, key):
if key in self._data:
del self._data[key]
def size(self):
return len(self._data)
Modellezhetjük a viselkedését, és tesztelhetjük egy állapotgéppel:
from hypothesis.stateful import RuleBasedStateMachine, rule, Bundle
class KeyValueStoreMachine(RuleBasedStateMachine):
def __init__(self):
super().__init__()
self.model = {}
self.sut = SimpleKeyValueStore()
# A Bundle() a szabályok közötti adatok átadására szolgál
keys = Bundle('keys')
@rule(target=keys, key=st.text(), value=st.integers())
def set_key(self, key, value):
self.model[key] = value
self.sut.set(key, value)
return key
@rule(key=keys)
def delete_key(self, key):
del self.model[key]
self.sut.delete(key)
@rule(key=st.text())
def get_key(self):
model_val = self.model.get(key)
sut_val = self.sut.get(key)
assert model_val == sut_val
@rule()
def check_size(self):
assert len(self.model) == self.sut.size()
# A teszt futtatásához egyszerűen örökölje az osztályt a gépből és a unittest.TestCase-ből
# Pytest-ben egyszerűen hozzárendelheti a tesztet a gép osztályához
TestKeyValueStore = KeyValueStoreMachine.TestCase
A Hypothesis most véletlenszerű `set_key`, `delete_key`, `get_key` és `check_size` műveletsorokat hajt végre, könyörtelenül próbálva olyan sorozatot találni, amely az egyik állítás hibájához vezet. Ellenőrzi, hogy egy törölt kulcs lekérése helyesen működik-e, hogy a méret konzisztens-e több beállítás és törlés után, és sok más forgatókönyvet, amelyekre manuálisan nem gondolna.
Bevált gyakorlatok és haladó tippek
- A példa adatbázis: A Hypothesis okos. Amikor hibát talál, elmenti a hibás példát egy helyi könyvtárba (
.hypothesis/). A következő alkalommal, amikor futtatja a tesztjeit, először ezt a hibás példát fogja újra lejátszani, azonnali visszajelzést adva arról, hogy a hiba még mindig fennáll. Amint kijavítja, a példa már nem kerül újra lejátszásra. - A tesztvégrehajtás szabályozása az
@settingssegítségével: A tesztfutás számos aspektusát szabályozhatja az@settingsdekorátorral. Növelheti a példák számát, határidőt állíthat be egyetlen példa futtatására (végtelen ciklusok elkapására), és kikapcsolhat bizonyos állapotellenőrzéseket.@settings(max_examples=500, deadline=1000) # Futtass 500 példát, 1 másodperces határidő @given(...) ...
- Hibák reprodukálása: Minden Hypothesis futtatás kiír egy seed értéket (pl.
@reproduce_failure('version', 'seed')). Ha egy CI szerver olyan hibát talál, amelyet Ön helyileg nem tud reprodukálni, használhatja ezt a dekorátort a megadott seed-del, hogy a Hypothesist ugyanazt a példasorozatot futtassa le. - Integráció CI/CD-vel: A Hypothesis tökéletesen illeszkedik bármely folyamatos integrációs pipeline-ba. Képessége, hogy ismeretlen hibákat találjon, mielőtt azok elérik a gyártást, felbecsülhetetlen értékű biztonsági hálóvá teszi.
A gondolkodásmódváltás: Tulajdonságokban való gondolkodás
A Hypothesis alkalmazása több, mint egy új könyvtár megtanulása; a kód helyességéről való gondolkodás új módjának elsajátításáról van szó. Ahelyett, hogy azt kérdezné: "Milyen bemeneteket teszteljek?", azt kezdi kérdezni: "Melyek a kódra vonatkozó egyetemes igazságok?"
Íme néhány kérdés, amelyek segítenek a tulajdonságok azonosításában:
- Létezik-e fordított művelet? (pl. szerializálás/deszerializálás, titkosítás/visszafejtés, tömörítés/kibontás). A tulajdonság az, hogy a művelet és annak fordítottja végrehajtása az eredeti bemenetet kell, hogy eredményezze.
- Idempotens-e a művelet? (pl.
abs(abs(x)) == abs(x)). A függvény többszöri alkalmazása ugyanazt az eredményt kell, hogy adja, mint az egyszeri alkalmazás. - Létezik-e egy másik, egyszerűbb módja ugyanaz eredmény kiszámításának? Tesztelheti, hogy a komplex, optimalizált függvénye ugyanazt a kimenetet produkálja-e, mint egy egyszerű, nyilvánvalóan helyes verzió (pl. a saját elegáns rendezőjének tesztelése a Python beépített
sorted()függvényével szemben). - Mi kell, hogy mindig igaz legyen a kimenetre vonatkozóan? (pl. egy `find_prime_factors` függvény kimenetének csak prím számokat kell tartalmaznia, és szorzatuknak meg kell egyeznie a bemenettel).
- Hogyan változik az állapot? (Állapot-alapú teszteléshez) Milyen invariánsokat kell fenntartani bármely érvényes művelet után? (pl. egy bevásárlókosárban lévő tételek száma soha nem lehet negatív).
Összefoglalás: Új szintű bizalom
A tulajdonság-alapú tesztelés a Hypothesis segítségével nem helyettesíti a példa-alapú tesztelést. Továbbra is szüksége van specifikus, kézzel írott tesztekre a kritikus üzleti logika és a jól ismert követelmények (pl. "Egy X országból származó felhasználónak Y árat kell látnia") esetében.
A Hypothesis egy hatékony, automatizált módszert biztosít a kód viselkedésének feltárására és az előre nem látott szélsőértékek elleni védelemre. Fáradhatatlan partnerként működik, több ezer olyan tesztet generálva, amelyek változatosabbak és ravaszabbak, mint amennyit bármely ember reálisan megírhatna. A kód alapvető tulajdonságainak meghatározásával egy robusztus specifikációt hoz létre, amelyet a Hypothesis tesztelhet, így új szintű bizalmat kap a szoftverében.
Amikor legközelebb ír egy függvényt, szánjon egy pillanatot arra, hogy túlmutasson a példákon. Kérdezze meg magától: "Mik a szabályok? Mi kell, hogy mindig igaz legyen?" Aztán hagyja, hogy a Hypothesis végezze el a kemény munkát, megpróbálva feltörni azokat. Meg fog lepődni, mit talál, és a kódja jobb lesz tőle.