Machine Learning

Vumela i-hypothesis iphule ikhodi yakho yePython ngaphambi kokuba abasebenzisi bakho benze

kufanele uthathe ngokungathi sína ikhodi yakho. Ungabhala izivivinyo zeyunithi ngePytest, ukuncika ukuncika, futhi ulwele ukumbozwa okuphezulu kwekhodi. Uma ufana nami, noma kunjalo, ungahle ube nombuzo onqenqemayo ohamba emuva emqondweni wakho ngemuva kokuqeda ukufaka amakhodi wokuhlola.

“Ngabe sengicabange ngawo wonke amacala onqenqemeni?”

Ungahlola okokufaka kwakho ngezinombolo ezinhle, izinombolo ezingezinhle, zero, nezintambo ezingenalutho. Kepha kuthiwani ngezinhlamvu ze-unicode ezixakile? Noma izinombolo ezintantayo ezintanta ezi-nan noma infinity? Kuthiwani ngohlu lwezinhlu zezintambo ezingenalutho noma i-json ye-json eyinkimbinkimbi? Isikhala sokufakwa okungenzeka sikhulu, futhi kunzima ukucabanga ngezindlela ezihlukile ze-MyRIAD ikhodi yakho engaqala ukuphula, ikakhulukazi uma ungaphansi kwengcindezi yesikhathi esithile.

Ukuhlolwa okususelwa empahleni kwezakhiwo kulo mthwalo kusuka nina kuya ekutholeni. Esikhundleni sezibonelo zokukha isandla, usho a impahla – Iqiniso okufanele libambe -nke okokufaka. Umtapo we-hypothesis ke veza okokufaka; amakhulu amaningana uma kudingeka, azingelwa ama-counterxamp, futhi – uma kuthola eyodwa – ukuncipha Kuyicala elilula kakhulu lehluleka.

Kulesi sihloko, ngizokungenisa emcabangweni onamandla wokuhlolwa okususelwa kwimpahla kanye nokuqaliswa kwawo nge-hypothesis. Sizohamba ngalé kwemisebenzi elula futhi sikukhombise ukuthi ungazihlola kanjani izakhiwo eziyinkimbinkimbi zedatha namakilasi asebenzayo, nokuthi ungayisebenzisa kanjani i-hypothesis enhle yokuhlola okuqinile nokusebenzayo.

Ngakho-ke, kuyini ngempela ukuhlolwa okusekelwe kwimpahla?

Ukuhlolwa okususelwa empahleni kuyindlela, lapho, esikhundleni sokubhala izivivinyo zezibonelo ezithile ezikhethekile, eziqinile, uchaza “izici” ezijwayelekile noma “ezihlasela” zekhodi yakho. Impahla iyisitatimende esisezingeni eliphakeme ngokuziphatha kwekhodi yakho okufanele ibambe -nke okokufaka okusebenzayo. Ngemuva kwalokho usebenzisa uhlaka lokuhlola, njenge-hypothesis, ekhiqiza ngokuqinile okufakwayo futhi izama ukuthola “isibonelo esiphikisayo” – uphawu oluthile lapho impahla yakho eshiwo khona.

Ezinye izici ezibalulekile zokuhlolwa okususelwa empahleni nge-hypothesis zifaka:

  • Ukuhlolwa okudala. I-Hypothesis yakha amacala okuhlola kuwe, kusuka kokulula kuya kwamacala onqenqemeni angajwayelekile, ahloliwe ongase uphuthelwe.
  • Eqhutshwa impahla. Ishintsha umqondo wakho kusuka ku- “Uyini umphumela wokufaka okuthile?” “Yini amaqiniso we-Universal mayelana nokuziphatha komsebenzi wami?”
  • Ukuncipha. Lesi yisici sokubulala sika-hypothesis. Lapho ithola icala lokuhlola elihlulekile (elingaba likhulu futhi liyinkimbinkimbi), aligcini nje ngokulibika. Ngokuzenzakalelayo “kuncipha” okufakwa phansi kusibonelo esincane kakhulu futhi esilula kunazo zonke esibangela ukwehluleka, kuvame ukwenza iphutha ngokudabukisayo.
  • Ukuhlolwa okuyisisekelo. I-Hypothesis ingavivinya imisebenzi emsulwa nje, kepha futhi nokusebenzisana kanye nokushintsha kwesimo kwezinto eziyinkimbinkimbi ngokulandelana kwezingcingo zendlela.
  • Amasu abizayo. I-Hypothesis ihlinzeka umtapo we- “Strategi” wokwenza idatha, futhi ikuvumela ukuba ubhale noma wakhe kahle kakhulu ukufanisa amamodeli wedatha yakho.

Kungani i-hypothesis izindaba / amacala ajwayelekile asetshenziswa

Inzuzo eyinhloko yokuhlolwa okususelwa empahleni yikhono layo lokuthola izimbungulu ezicashile futhi wandise ukuzethemba kwakho ngokunemba kwekhodi yakho kude nalokho okungenzeka ngokuhlolwa okusekelwe kwisibonelo. Kukuphoqa ukuthi ucabange kakhulu ngezinkontileka kanye nemibono yekhodi yakho.

I-Hypothesis isebenza kahle kakhulu ekuhlolweni:

  • Ukuhlukaniswa / deserialisation. Impahla yakudala ukuthi kunoma iyiphi into x, income (encode (x)) kufanele ilingane no-x. Lokhu kulungele imisebenzi yokuhlola esebenza nge-JSON noma amafomethi ka-Binary.
  • I-Complex Business Logic. Noma yimuphi umsebenzi one-logic eyinkimbinkimbi enemibandela ngumuntu okhethwayo omkhulu. I-Hypothesis izohlola izindlela ngekhodi yakho okungenzeka ukuthi awuyicubunguli.
  • Izinhlelo ezivelelayo. Amakilasi okuhlola nezinto ukuqinisekisa ukuthi akukho ukulandelana kwemisebenzi evumelekile kungabeka into ibe yisimo esonakele noma esingalungile.
  • Ukuhlola ukuqaliswa kokuqaliswa kwesethenjwa. Ungasho impahla ukuthi umsebenzi wakho omusha, owenziwe kahle kufanele ukhiqize umphumela ofanayo nokwenziwa okuqondile, okwenziwe ngokwesibonelo.
  • Imisebenzi eyamukela amamodeli ayinkimbinkimbi wedatha. Imisebenzi yokuhlola ethatha amamodeli wePydantic, ama-DACACLASS, noma ezinye izinto zangokwezifiso njengokufaka.

Ukusetha imvelo yokuthuthuka

Konke okudingayo yiPython nePip. Sizofaka i-Pytest njengoba umgijimi wethu wokuhlola, i-hypothesis uqobo, futhi i-pydantic ngesinye sezibonelo zethu ezithuthukile.

(base) tom@tpr-desktop:~$ python -m venv hyp-env
(base) tom@tpr-desktop:~$ source hyp-env/bin/activate
(hyp-env) (base) tom@tpr-desktop:~$

# Install pytest, hypothesis, and pydantic
(hyp-env) (base) tom@tpr-desktop:~$ pip install pytest hypothesis pydantic 

# create a new folder to hold your python code
(hyp-env) (base) tom@tpr-desktop:~$ mkdir hyp-project

I-Hypothesis isebenza kangcono ngokusebenzisa ithuluzi lokuqalisa lokuhlola elisunguliwe njengePytest, ngakho-ke yilokho esikwenzayo lapha.

Isibonelo sekhodi 1 – isivivinyo esilula

Kulesi zibonelo ezilula kakhulu, sinomsebenzi onquma indawo yoxande. Kufanele kuthathe amapharamitha amabili we-Integer, amakhulu kune-zero, futhi abuyise umkhiqizo wawo.

Ukuhlolwa kwe-hypothesis kuchazwa kusetshenziswa izinto ezimbili: The @gonvenumhlobiso no icebo odluliswa kumhlobiso. Cabanga ngecebo njengezinhlobo zedatha ezithi hypothesi zizokhiqiza ukuze zivivinye umsebenzi wakho. Nasi isibonelo esilula. Okokuqala, sichaza umsebenzi esifuna ukuwuhlola.

# my_geometry.py

def calculate_rectangle_area(length: int, width: int) -> int:
  """
  Calculates the area of a rectangle given its length and width.

  This function raises a ValueError if either dimension is not a positive integer.
  """
  if not isinstance(length, int) or not isinstance(width, int):
    raise TypeError("Length and width must be integers.")
  
  if length <= 0 or width <= 0:
    raise ValueError("Length and width must be positive.")
  
  return length * width

Okulandelayo umsebenzi wokuhlola.

# test_rectangle.py

from my_geometry import calculate_rectangle_area
from hypothesis import given, strategies as st
import pytest

# By using st.integers(min_value=1) for both arguments, we guarantee
# that Hypothesis will only generate valid inputs for our function.
@given(
    length=st.integers(min_value=1), 
    width=st.integers(min_value=1)
)
def test_rectangle_area_with_valid_inputs(length, width):
    """
    Property: For any positive integers length and width, the area
    should be equal to their product.
    
    This test ensures the core multiplication logic is correct.
    """
    print(f"Testing with valid inputs: length={length}, width={width}")
    
    # The property we are checking is the mathematical definition of area.
    assert calculate_rectangle_area(length, width) == length * width

Ukungeza @gonven Umhlobiso emsebenzini awuguqula ekuhlolweni kwe-hypothesis. Ukudlulisa isu (iSt.integer) kumhlobisi uthi i-hypothesis kufanele ikhiqize izinombolo ezingahleliwe ngengxabano ni Lapho uvivinywa, kepha siqhubeka nokucindezela ukuthi ngokuqinisekisa ukuthi ama-Integer angaba ngaphansi koyedwa.

Singalisebenzisa lolu vivinyo ngokulibiza ngale ndlela.

(hyp-env) (base) tom@tpr-desktop:~/hypothesis_project$ pytest -s test_my_geometry.py

=========================================== test session starts ============================================
platform linux -- Python 3.11.10, pytest-8.4.0, pluggy-1.6.0
rootdir: /home/tom/hypothesis_project
plugins: hypothesis-6.135.9, anyio-4.9.0
collected 1 item

test_my_geometry.py Testing with valid inputs: length=1, width=1
Testing with valid inputs: length=6541, width=1
Testing with valid inputs: length=6541, width=28545
Testing with valid inputs: length=1295885530, width=1
Testing with valid inputs: length=1295885530, width=25191
Testing with valid inputs: length=14538, width=1
Testing with valid inputs: length=14538, width=15503
Testing with valid inputs: length=7997, width=1
...
...

Testing with valid inputs: length=19378, width=22512
Testing with valid inputs: length=22512, width=22512
Testing with valid inputs: length=3392, width=44
Testing with valid inputs: length=44, width=44
.

============================================ 1 passed in 0.10s =============================================

Ngokuzenzakalelayo, i-hypothesis izokwenza izivivinyo eziyi-100 emsebenzini wakho ngokufaka okuhlukile. Ungakhuphula noma wehlise lokhu ngokusebenzisa amasethingi umhlobiso. Ngokwesibonelo,

from hypothesis import given, strategies as st,settings
...
...
@given(
    length=st.integers(min_value=1), 
    width=st.integers(min_value=1)
)
@settings(max_examples=3)
def test_rectangle_area_with_valid_inputs(length, width):
...
...

#
# Outputs
#
(hyp-env) (base) tom@tpr-desktop:~/hypothesis_project$ pytest -s test_my_geometry.py
=========================================== test session starts ============================================
platform linux -- Python 3.11.10, pytest-8.4.0, pluggy-1.6.0
rootdir: /home/tom/hypothesis_project
plugins: hypothesis-6.135.9, anyio-4.9.0
collected 1 item

test_my_geometry.py 
Testing with valid inputs: length=1, width=1
Testing with valid inputs: length=1870, width=5773964720159522347
Testing with valid inputs: length=61, width=25429
.

============================================ 1 passed in 0.06s =============================================

Isibonelo sekhodi 2 – Ukuhlola impahla ye-classic “yokujikeleza”

Ake sibheke impahla yakudala: – Ukuqina nokusebenziseka kabusha kufanele kubuye kube nokuguqulwa. Ngamafuphi, incomu (encode (x)) kufanele ibuye u-X.

Sizobhala umsebenzi othatha isichazamazwi bese usifaka kwintambo yemibuzo ye-URL.

Dala ifayela kufolda yakho yeProp-Project Folject egama layo lingu-My_cedoders.PY.

# my_encoders.py
import urllib.parse

def encode_dict_to_querystring(data: dict) -> str:
    # A bug exists here: it doesn't handle nested structures well
    return urllib.parse.urlencode(data)

def decode_querystring_to_dict(qs: str) -> dict:
    return dict(urllib.parse.parse_qsl(qs))

Le yimisebenzi emibili yokuqala. Yini engahamba kahle ngayo? Manje ake uzihlole ku-test_cencoders.py:
# tenctoders.py

# test_encoders.py

from hypothesis import given, strategies as st

# A strategy for generating dictionaries with simple text keys and values
simple_dict_strategy = st.dictionaries(keys=st.text(), values=st.text())

@given(data=simple_dict_strategy)
def test_querystring_roundtrip(data):
    """Property: decoding an encoded dict should yield the original dict."""
    encoded = encode_dict_to_querystring(data)
    decoded = decode_querystring_to_dict(encoded)
    
    # We have to be careful with types: parse_qsl returns string values
    # So we convert our original values to strings for a fair comparison
    original_as_str = {k: str(v) for k, v in data.items()}
    
    assert decoded == original_as_st

Manje sesingakuqhuba isivivinyo sethu.

(hyp-env) (base) tom@tpr-desktop:~/hypothesis_project$ pytest -s test_encoders.py
=========================================== test session starts ============================================
platform linux -- Python 3.11.10, pytest-8.4.0, pluggy-1.6.0
rootdir: /home/tom/hypothesis_project
plugins: hypothesis-6.135.9, anyio-4.9.0
collected 1 item

test_encoders.py F

================================================= FAILURES =================================================
_______________________________________ test_for_nesting_limitation ________________________________________

    @given(data=st.recursive(
>       # Base case: A flat dictionary of text keys and simple values (text or integers).
                   ^^^
        st.dictionaries(st.text(), st.integers() | st.text()),
        # Recursive step: Allow values to be dictionaries themselves.
        lambda children: st.dictionaries(st.text(), children)
    ))

test_encoders.py:7:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

data = {'': {}}

    @given(data=st.recursive(
        # Base case: A flat dictionary of text keys and simple values (text or integers).
        st.dictionaries(st.text(), st.integers() | st.text()),
        # Recursive step: Allow values to be dictionaries themselves.
        lambda children: st.dictionaries(st.text(), children)
    ))
    def test_for_nesting_limitation(data):
        """
        This test asserts that the decoded data structure matches the original.
        It will fail because urlencode flattens nested structures.
        """
        encoded = encode_dict_to_querystring(data)
        decoded = decode_querystring_to_dict(encoded)

        # This is a deliberately simple assertion. It will fail for nested
        # dictionaries because the `decoded` version will have a stringified
        # inner dict, while the `data` version will have a true inner dict.
        # This is how we reveal the bug.
>       assert decoded == data
E       AssertionError: assert {'': '{}'} == {'': {}}
E
E         Differing items:
E         {'': '{}'} != {'': {}}
E         Use -v to get more diff
E       Falsifying example: test_for_nesting_limitation(
E           data={'': {}},
E       )

test_encoders.py:24: AssertionError
========================================= short test summary info ==========================================
FAILED test_encoders.py::test_for_nesting_limitation - AssertionError: assert {'': '{}'} == {'': {}}

Kulungile, lokho bekungalindelekile. Ake sizame ukunquma okungahambanga kahle ngalolu vivinyo. I-TL; u-DR ukuthi lokhu kuhlolwa kukhombisa imisebenzi ye-encode / decode akusebenzi kahle izichazamazwi ezidliwe.

  • Isibonelo Samanga. Inkomba ebaluleke kakhulu isezansi. I-Hypothesis isitshela Okokufaka okuqondile lokho kwephula ikhodi.
test_for_nesting_limitation(
    data={'': {}},
)
  • Ukufakwa yisichazamazwi lapho ukhiye uyintambo engenalutho futhi inani lesichazamazwi esingenalutho. Leli yicala elisezingeni eliphezulu umuntu angawanaki.
  • Iphutha lokuvuma: Ukuhlolwa kwehlulekile ngenxa yesitatimende se-Afvert Sounts:
AssertionError: assert {'': '{}'} == {'': {}}

Lokhu kungumongo wenkinga. Idatha yoqobo eyangena ekuhlolweni yayingu- {'': {}}. Umphumela ohlonishwayo ophume emisebenzini yakho wawungu- {'': '{{{{{}'}}. Lokhu kukhombisa ukuthi kukhiye '', amanani ahlukile:

  • Ku-decoded, inani yilona intambo '{{}'.
  • Kudatha, inani yilona isichazimazwi {}.

Intambo ayilingani nesichazamazwi, ngakho-ke ukugomela godule decoded == idathaIS -Namangafuthi ukuhlolwa kwehluleka.

Ukulandela i-Bug Step-Step

Umsebenzi wethu we-Encode_DicT_TO_Querystrung usebenzisa i-URLLIB.Parse.urlencode. Lapho i-URLENCECODODODODODODODE ibona inani lesichazamazwi (njenge- {}), alazi ukuthi liyasingatha kanjani, ngakho-ke livele likuguqulele ekumeleleni kwentambo ('{{}').

Imininingwane mayelana nenani langempelaukuthayipha (ukuthi bekuyinto elahlekile unomphela .

Lapho i-demode_querystring_to_dind umsebenzi ufunda idatha emuva, ibeka kahle inani njengentambo '{{}'. Akunandlela yokwazi ukuthi ekuqaleni isichazamazwi.

Isixazululo: Kuhlelwa amanani anezinhlaka ezihlanganisiwe njengezintambo ze-json

Isixazululo silula,

  1. Enyede. Ngaphambi kwe-URL-Encoding, hlola inani ngalinye kwisichazamazwi sakho. Uma inani liyi-dict noma uhlu, liguqule libe yi-JSON String kuqala.
  2. Nquma. Ngemuva kwe-URL-Decoding, hlola inani ngalinye. Uma inani libukeka njengentambo ye-json (isib., Iqala ngo- {noma [), parse it back into a Python object.
  3. Make our testing more comprehensive. Our given decorator is more complex. In simple terms, it tells Hypothesis to generate dictionaries that can contain other dictionaries as values, allowing for nested data structures of any depth. For example, 
  • A simple, flat dictionary: {‘name’: ‘Alice’, ‘city’: ‘London’}
  • A one-level nested dictionary: {‘user’: {‘id’: ‘123’, ‘name’: ‘Tom’}}
  • A two-level nested dictionary: {‘config’: {‘database’: {‘host’: ‘localhost’}}}
  • And so on…

Here is the fixed code.

# test_encoders.py

from my_encoders import encode_dict_to_querystring, decode_querystring_to_dict
from hypothesis import given, strategies as st

# =========================================================================
# TEST 1: This test proves that the NESTING logic is correct.
# It uses a strategy that ONLY generates strings, so we don't have to
# worry about type conversion. This test will PASS.
# =========================================================================
@given(data=st.recursive(
    st.dictionaries(st.text(), st.text()),
    lambda children: st.dictionaries(st.text(), children)
))
def test_roundtrip_preserves_nested_structure(data):
    """Property: The encode/decode round-trip should preserve nested structures."""
    encoded = encode_dict_to_querystring(data)
    decoded = decode_querystring_to_dict(encoded)
    assert decoded == data

# =========================================================================
# TEST 2: This test proves that the TYPE CONVERSION logic is correct
# for simple, FLAT dictionaries. This test will also PASS.
# =========================================================================
@given(data=st.dictionaries(st.text(), st.integers() | st.text()))
def test_roundtrip_stringifies_simple_values(data):
    """
    Property: The round-trip should convert simple values (like ints)
    to strings.
    """
    encoded = encode_dict_to_querystring(data)
    decoded = decode_querystring_to_dict(encoded)

    # Create the model of what we expect: a dictionary with stringified values.
    expected_data = {k: str(v) for k, v in data.items()}
    assert decoded == expected_data

Now, if we rerun our test, we get this,

(hyp-env) (base) tom@tpr-desktop:~/hypothesis_project$ pytest
=========================================== test session starts ============================================
platform linux -- Python 3.11.10, pytest-8.4.0, pluggy-1.6.0
rootdir: /home/tom/hypothesis_project
plugins: hypothesis-6.135.9, anyio-4.9.0
collected 1 item

test_encoders.py .                                                                                   [100%]

================================================================================================================================================================================================= 1

Esikusebenzisile lapho kunesibonelo sakudala sibonisa ukuthi kungaba kanjani ukuhlolwa okuwusizo nge-hypothesis. Lokho ebesikucabanga ukuthi yimisebenzi emibili elula futhi engenaphutha-ngaphandle akufanele kube njalo.

Isibonelo sekhodi 3- Ukwakha isu langokwezifiso lemodeli yePydantic

Imisebenzi eminingi yomhlaba wangempela ayithathi nje izichazamazwi ezilula; Bathatha izinto ezihlelekile njengemodeli yePydantic. I-Hypothesisis ingakha amasu alezi zinhlobo zenkambiso, futhi.

Masichaze imodeli kuma-men_models.py.

# my_models.py
from pydantic import BaseModel, Field
from typing import List

class Product(BaseModel):
    id: int = Field(gt=0)
    name: str = Field(min_length=1)
    tags: List[str]
def calculate_shipping_cost(product: Product, weight_kg: float) -> float:
    # A buggy shipping cost calculator
    cost = 10.0 + (weight_kg * 1.5)
    if "fragile" in product.tags:
        cost *= 1.5 # Extra cost for fragile items
    if weight_kg > 10:
        cost += 20 # Surcharge for heavy items
    # Bug: what if cost is negative?
    return cost

Manje, ekuhlolweni_pshipping.PY, sizokwakha isu lokukhiqiza izimo zomkhiqizo futhi sivivinye umsebenzi wethu we-buggy.

# test_shipping.py
from my_models import Product, calculate_shipping_cost
from hypothesis import given, strategies as st

# Build a strategy for our Product model
product_strategy = st.builds(
    Product,
    id=st.integers(min_value=1),
    name=st.text(min_size=1),
    tags=st.lists(st.sampled_from(["electronics", "books", "fragile", "clothing"]))
)
@given(
    product=product_strategy,
    weight_kg=st.floats(min_value=-10, max_value=100, allow_nan=False, allow_infinity=False)
)
def test_shipping_cost_is_always_positive(product, weight_kg):
    """Property: The shipping cost should never be negative."""
    cost = calculate_shipping_cost(product, weight_kg)
    assert cost >= 0

Kanye nokuphuma kokuhlola?

(hyp-env) (base) tom@tpr-desktop:~/hypothesis_project$ pytest -s test_shipping.py
========================================================= test session starts ==========================================================
platform linux -- Python 3.11.10, pytest-8.4.0, pluggy-1.6.0
rootdir: /home/tom/hypothesis_project
plugins: hypothesis-6.135.9, anyio-4.9.0
collected 1 item

test_shipping.py F

=============================================================== FAILURES ===============================================================
________________________________________________ test_shipping_cost_is_always_positive _________________________________________________

    @given(
>       product=product_strategy,
                   ^^^
        weight_kg=st.floats(min_value=-10, max_value=100, allow_nan=False, allow_infinity=False)
    )

test_shipping.py:13:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

product = Product(id=1, name='0', tags=[]), weight_kg = -7.0

    @given(
        product=product_strategy,
        weight_kg=st.floats(min_value=-10, max_value=100, allow_nan=False, allow_infinity=False)
    )
    def test_shipping_cost_is_always_positive(product, weight_kg):
        """Property: The shipping cost should never be negative."""
        cost = calculate_shipping_cost(product, weight_kg)
>       assert cost >= 0
E       assert -0.5 >= 0
E       Falsifying example: test_shipping_cost_is_always_positive(
E           product=Product(id=1, name='0', tags=[]),
E           weight_kg=-7.0,
E       )

test_shipping.py:19: AssertionError
======================================================= short test summary info ========================================================
FAILED test_shipping.py::test_shipping_cost_is_always_positive - assert -0.5 >= 0
========================================================== 1 failed in 0.12s ===========================================================

Lapho uqhuba lokhu nge-Pytest, i-hypothesis izothola ngokushesha isibonelo se-falductised: umkhiqizo onesisindo esingesihle_kg kungaholela ezindlekweni ezingezinhle zokuthumela. Leli yicala eliseceleni okungenzeka asilicubungule, kepha i-hypothesis yakuthola ngokuzenzakalelayo.

Isibonelo sekhodi 4- Ukuhlola amakilasi abonakalayo

I-Hypothesis ingenza okungaphezu kokuhlola imisebenzi emsulwa. Kungahlola amakilasi ngesimo sangaphakathi ngokukhiqiza ukulandelana kwezingcingo zendlela izingcingo ukuzama ukuwaphula. Ake sihlole isigaba esilinganiselwe senkampani esilinganiselwe.

i -_cache.py yami.PY

# my_cache.py
class LimitedCache:
    def __init__(self, capacity: int):
        if capacity <= 0:
            raise ValueError("Capacity must be positive")
        self._cache = {}
        self._capacity = capacity
        # Bug: This should probably be a deque or ordered dict for proper LRU
        self._keys_in_order = []

    def put(self, key, value):
        if key not in self._cache and len(self._cache) >= self._capacity:
            # Evict the oldest item
            key_to_evict = self._keys_in_order.pop(0)
            del self._cache[key_to_evict]
        
        if key not in self._keys_in_order:
            self._keys_in_order.append(key)
        self._cache[key] = value

    def get(self, key):
        return self._cache.get(key)
   
    @property
    def size(self):
        return len(self._cache)

Lesi silondolozi sinezimbungulu eziningana ezingaba khona ezihlobene nenqubomgomo yazo yokuxoshwa. Ake sikuhlole sisebenzisa umshini wombuso osuselwa ku-hypothesis, eyenzelwe ukuhlola izinto ezinesimo sangaphakathi ngokukhiqiza ukulandelana okungahleliwe kwezingcingo ezivela ekubonisweni okuvela kuphela ngemuva kokusebenzisana okuthile.

Dala i-Test Test_Cow.Py.

from hypothesis import strategies as st
from hypothesis.stateful import RuleBasedStateMachine, rule, precondition
from my_cache import LimitedCache

class CacheMachine(RuleBasedStateMachine):
    def __init__(self):
        super().__init__()
        self.cache = LimitedCache(capacity=3)

    # This rule adds 3 initial items to fill the cache
    @rule(
        k1=st.just('a'), k2=st.just('b'), k3=st.just('c'),
        v1=st.integers(), v2=st.integers(), v3=st.integers()
    )
    def fill_cache(self, k1, v1, k2, v2, k3, v3):
        self.cache.put(k1, v1)
        self.cache.put(k2, v2)
        self.cache.put(k3, v3)

    # This rule can only run AFTER the cache has been filled.
    # It tests the core logic of LRU vs FIFO.
    @precondition(lambda self: self.cache.size == 3)
    @rule()
    def test_update_behavior(self):
        """
        Property: Updating the oldest item ('a') should make it the newest,
        so the next eviction should remove the second-oldest item ('b').
        Our buggy FIFO cache will incorrectly remove 'a' anyway.
        """
        # At this point, keys_in_order is ['a', 'b', 'c'].
        # 'a' is the oldest.
        
        # We "use" 'a' again by updating it. In a proper LRU cache,
        # this would make 'a' the most recently used item.
        self.cache.put('a', 999) 
        
        # Now, we add a new key, which should force an eviction.
        self.cache.put('d', 4)

        # A correct LRU cache would evict 'b'.
        # Our buggy FIFO cache will evict 'a'.
        # This assertion checks the state of 'a'.
        # In our buggy cache, get('a') will be None, so this will fail.
        assert self.cache.get('a') is not None, "Item 'a' was incorrectly evicted"
        
# This tells pytest to run the state machine test
TestCache = CacheMachine.TestCase

I-Hypothesis izokhiqiza ukulandelana okude kokubeka futhi kutholakale. Izokhomba ngokushesha ukulandelana kwamatshe okudala usayizi we-cache ukwedlula amandla ayo noma ngokuxoshwa kwawo ukuze uziphathe ngendlela ehlukile kwimodeli yethu, ngaleyo ndlela aveze izimbungulu ekusetshenzisweni kwethu.

(hyp-env) (base) tom@tpr-desktop:~/hypothesis_project$ pytest -s test_cache.py
========================================================= test session starts ==========================================================
platform linux -- Python 3.11.10, pytest-8.4.0, pluggy-1.6.0
rootdir: /home/tom/hypothesis_project
plugins: hypothesis-6.135.9, anyio-4.9.0
collected 1 item

test_cache.py F

=============================================================== FAILURES ===============================================================
__________________________________________________________ TestCache.runTest ___________________________________________________________

self = 

    def runTest(self):
>       run_state_machine_as_test(cls, settings=self.settings)

../hyp-env/lib/python3.11/site-packages/hypothesis/stateful.py:476:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../hyp-env/lib/python3.11/site-packages/hypothesis/stateful.py:258: in run_state_machine_as_test
    state_machine_test(state_machine_factory)
../hyp-env/lib/python3.11/site-packages/hypothesis/stateful.py:115: in run_state_machine
    @given(st.data())
               ^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = CacheMachine({})

    @precondition(lambda self: self.cache.size == 3)
    @rule()
    def test_update_behavior(self):
        """
        Property: Updating the oldest item ('a') should make it the newest,
        so the next eviction should remove the second-oldest item ('b').
        Our buggy FIFO cache will incorrectly remove 'a' anyway.
        """
        # At this point, keys_in_order is ['a', 'b', 'c'].
        # 'a' is the oldest.

        # We "use" 'a' again by updating it. In a proper LRU cache,
        # this would make 'a' the most recently used item.
        self.cache.put('a', 999)

        # Now, we add a new key, which should force an eviction.
        self.cache.put('d', 4)

        # A correct LRU cache would evict 'b'.
        # Our buggy FIFO cache will evict 'a'.
        # This assertion checks the state of 'a'.
        # In our buggy cache, get('a') will be None, so this will fail.
>       assert self.cache.get('a') is not None, "Item 'a' was incorrectly evicted"
E       AssertionError: Item 'a' was incorrectly evicted
E       assert None is not None
E        +  where None = get('a')
E        +    where get = .get
E        +      where  = CacheMachine({}).cache
E       Falsifying example:
E       state = CacheMachine()
E       state.fill_cache(k1='a', k2='b', k3='c', v1=0, v2=0, v3=0)
E       state.test_update_behavior()
E       state.teardown()

test_cache.py:44: AssertionError
======================================================= short test summary info ========================================================
FAILED test_cache.py::TestCache::runTest - AssertionError: Item 'a' was incorrectly evicted
========================================================== 1 failed in 0.20s ===========================================================

Ukukhishwa okungenhla kuqokomisa isiphazamiso kwikhodi. Ngamagama alula, lokhu kukhipha kukhombisa ukuthi i-cache ingukuthi hhayi okufanele “Okuncane okusetshenzisiwe” (lru) isilondolozi. Inephutha elilandelayo elilandelayo,

Lapho uvuselela into esevele iku-cache, i-cache yehluleka ukukhumbula ukuthi manje sekuyinto “entsha”. Kusakuphatha njengokudala, ngakho-ke kuyakhishwa (kuxoshwa) kusuka ku-cache ngaphambi kwesikhathi.

Isibonelo sekhodi 5 – Ukuhlolwa ngokumelene nokuqaliswa okulula, okubhekwayo

Isibonelo sethu sokugcina, sizobheka isimo esivamile. Imvamisa, ama-coders abhala imisebenzi okumele ithathe indawo endala, kancane, kepha ngenye indlela efanelekile, imisebenzi. Umsebenzi wakho omusha kufanele ube nemiphumela efanayo njengomsebenzi wakudala wokufaka okufanayo. I-hypothesise ingenza ukuhlolwa kwakho kulokhu kube lula kakhulu.

Ake sithi sinomsebenzi olula, sum_list_simple, kanye okusha, “Kwenzelwe” sum_list_fast enesiphazamiso.

my_sums.py

# my_sums.py
def sum_list_simple(data: list[int]) -> int:
    # This is our simple, correct reference implementation
    return sum(data)

def sum_list_fast(data: list[int]) -> int:
    # A new "fast" implementation with a bug (e.g., integer overflow for large numbers)
    # or in this case, a simple mistake.
    total = 0
    for x in data:
        # Bug: This should be +=
        total = x
    return total

test_sums.py

# test_sums.py
from my_sums import sum_list_simple, sum_list_fast
from hypothesis import given, strategies as st

@given(st.lists(st.integers()))
def test_fast_sum_matches_simple_sum(data):
    """
    Property: The result of the new, fast function should always match
    the result of the simple, reference function.
    """
    assert sum_list_fast(data) == sum_list_simple(data)

I-Hypothesis izothola ngokushesha lokho kunoma yiluphi uhlu olunento engaphezu kweyodwa, umsebenzi omusha wehluleka. Ake sikuhlole.

(hyp-env) (base) tom@tpr-desktop:~/hypothesis_project$ pytest -s test_my_sums.py
=========================================== test session starts ============================================
platform linux -- Python 3.11.10, pytest-8.4.0, pluggy-1.6.0
rootdir: /home/tom/hypothesis_project
plugins: hypothesis-6.135.9, anyio-4.9.0
collected 1 item

test_my_sums.py F

================================================= FAILURES =================================================
_____________________________________ test_fast_sum_matches_simple_sum _____________________________________

    @given(st.lists(st.integers()))
>   def test_fast_sum_matches_simple_sum(data):
                   ^^^

test_my_sums.py:6:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

data = [1, 0]

    @given(st.lists(st.integers()))
    def test_fast_sum_matches_simple_sum(data):
        """
        Property: The result of the new, fast function should always match
        the result of the simple, reference function.
        """
>       assert sum_list_fast(data) == sum_list_simple(data)
E       assert 0 == 1
E        +  where 0 = sum_list_fast([1, 0])
E        +  and   1 = sum_list_simple([1, 0])
E       Falsifying example: test_fast_sum_matches_simple_sum(
E           data=[1, 0],
E       )

test_my_sums.py:11: AssertionError
========================================= short test summary info ==========================================
FAILED test_my_sums.py::test_fast_sum_matches_simple_sum - assert 0 == 1
============================================ 1 failed in 0.17s =============================================

Ngakho-ke, isivivinyo sehlulekile ngoba “Kuyashesha” Umsebenzi we-Sum unikeze impendulo engalungile (0) yohlu lokufaka [1, 0]ngenkathi impendulo efanele, enikezwe yi “Elula”Umsebenzi we-Sum, wawungu-1. Manje njengoba uyayazi inkinga, ungathatha izinyathelo zokuyilungisa.

Ukubeka kafushane

Kulesi sihloko, sangena emanzini ajulile ekuhlolweni okusekelwe empahleni nge-hypothesis, sihamba ngalezi zibonelo ezilula ukukhombisa ukuthi zingasetshenziswa kanjani ezinhlelweni zokuhlola umhlaba wangempela. Sikubonile ukuthi ngokuchaza izisulu zekhodi yethu, singathola ukuthola izimbungulu ezicashile ukuthi kuzokuphuthelwa ukuhlolwa kwendabuko. Sifunde ukuthi:

  • Hlola impahla ethi “Round-Trive” bese ubona ukuthi amasu ayinkimbinkimbi wedatha angaveza imikhawulo kwikhodi yethu.
  • Yakha amasu wangokwezifiso ukukhiqiza izimo zamamodeli ayinkimbinkimbi wePydantic for viving logic yebhizinisi.
  • Sebenzisa i-RulebasedStatemachine ukuhlola ukusebenza kwamakilasi avelelayo ngokukhiqiza ukulandelana kwezingcingo zendlela.
  • Qinisekisa umsebenzi oyinkimbinkimbi, olungiselelwe ngokuyihlola ngokumelene nokuqaliswa okuqondile, okuhlelekile kwesethenjwa.

Ukungeza izivivinyo ezenzelwe impahla ku-ToolKit yakho ngeke zithathe indawo yakho yonke ekhona. Noma kunjalo, kuzokuthola kakhulu, kukuphoqa ukuthi ucabange ngokucacile ngezinkontileka zekhodi yakho futhi unikeze inani eliphakeme kakhulu lokuzethemba ngokunemba kwalo. Ngikugqugquzela ukuthi ukhethe umsebenzi noma isigaba ku-codebase yakho, cabanga ngezakhiwo zayo eziyisisekelo, futhi vumela i-hypothesis izama konke okusemandleni ukukufakazela ukuthi unephutha. Uzoba ngunjiniyela ongcono ngakho.

Ngike ngagxuma kuphela lapho i-hypothesis ingenzani ngokuhlolwa kwakho. Ngeminye imininingwane, bheka imibhalo yabo esemthethweni, etholakala ngesixhumanisi esingezansi.

Source link

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button