Python'ın Hypothesis kütüphanesi ile özellik temelli testleri keşfedin. Kenar durumları bulmak ve daha sağlam, güvenilir yazılımlar oluşturmak için örnek tabanlı testlerin ötesine geçin.
Birim Testlerinin Ötesinde: Python'ın Hypothesis'i ile Özellik Temelli Testlere Derinlemesine Bir Bakış
Yazılım geliştirme dünyasında, test etme kalitenin temel taşıdır. Onlarca yıldır, baskın paradigma örnek tabanlı test olmuştur. Girdileri titizlikle hazırlar, beklenen çıktıları tanımlar ve kodumuzun planlandığı gibi davrandığını doğrulamak için onaylar yazarız. unittest
ve pytest
gibi çerçevelerde bulunan bu yaklaşım güçlü ve esastır. Ama size hiç bakmayı düşünmediğiniz hataları ortaya çıkarabilen tamamlayıcı bir yaklaşım olduğunu söyleseydim?
Özellik tabanlı test dünyasına hoş geldiniz; odak noktasını belirli örnekleri test etmekten, kodunuzun genel özelliklerini doğrulamaya kaydıran bir paradigma. Ve Python ekosisteminde, bu yaklaşımın tartışmasız şampiyonu Hypothesis adlı bir kütüphanedir.
Bu kapsamlı rehber, tamamen yeni başlayanlardan, Hypothesis ile özellik tabanlı testlerin güvenilir bir uygulayıcısına kadar sizi götürecektir. Temel kavramları keşfedecek, pratik örneklere dalacak ve daha sağlam, güvenilir ve hataya dayanıklı yazılımlar oluşturmak için bu güçlü aracı günlük geliştirme iş akışınıza nasıl entegre edeceğinizi öğreneceğiz.
Özellik Temelli Test Nedir? Zihniyette Bir Değişim
Hypothesis'i anlamak için, önce özellik tabanlı testin temel fikrini kavramamız gerekir. Bunu, hepimizin bildiği geleneksel örnek tabanlı testle karşılaştıralım.
Örnek Tabanlı Test: Tanıdık Yol
Özel bir sıralama fonksiyonu olan my_sort()
yazdığınızı hayal edin. Örnek tabanlı test ile düşünce süreciniz şöyle olacaktır:
- "Basit, sıralı bir liste ile test edelim." ->
assert my_sort([1, 2, 3]) == [1, 2, 3]
- "Ya ters sıralı bir liste?" ->
assert my_sort([3, 2, 1]) == [1, 2, 3]
- "Boş bir liste nasıl olur?" ->
assert my_sort([]) == []
- "Yinelenen öğeler içeren bir liste?" ->
assert my_sort([5, 1, 5, 2]) == [1, 2, 5, 5]
- "Ve negatif sayılar içeren bir liste?" ->
assert my_sort([-1, -5, 0]) == [-5, -1, 0]
Bu etkilidir, ancak temel bir sınırlaması vardır: yalnızca düşünebildiğiniz durumları test edersiniz. Testleriniz yalnızca hayal gücünüz kadar iyidir. Çok büyük sayılar, kayan nokta hataları, belirli unicode karakterleri veya beklenmedik davranışlara yol açan karmaşık veri kombinasyonları içeren kenar durumları kaçırabilirsiniz.
Özellik Tabanlı Test: Değişmezlerde Düşünmek
Özellik tabanlı test senaryoyu tersine çevirir. Belirli örnekler sağlamak yerine, fonksiyonunuzun özelliklerini veya değişmezlerini tanımlarsınız—herhangi bir geçerli girdi için doğru olması gereken kurallar. my_sort()
fonksiyonumuz için bu özellikler şunlar olabilir:
- Çıktı sıralanmıştır: Herhangi bir sayı listesi için, çıktı listesindeki her öğe, onu izleyen öğeden küçüktür veya ona eşittir.
- Çıktı, girdilerle aynı öğeleri içerir: Sıralanmış liste, orijinal listenin sadece bir permütasyonudur; hiçbir öğe eklenmez veya kaybolmaz.
- Fonksiyon idempotenttir: Zaten sıralanmış bir listeyi sıralamak onu değiştirmemelidir. Yani,
my_sort(my_sort(some_list)) == my_sort(some_list)
.
Bu yaklaşımla, test verilerini yazmıyorsunuz. Kuralları yazıyorsunuz. Daha sonra, Hypothesis gibi bir çerçeveye, özelliklerinizi yanlış kanıtlamaya çalışmak için yüzlerce veya binlerce rastgele, çeşitli ve genellikle sinsi girdi oluşturmasına izin verirsiniz. Bir özelliği bozan bir girdi bulursa, bir hata bulmuş demektir.
Hypothesis'i Tanıtalım: Otomatik Test Veri Üreticiniz
Hypothesis, Python için önde gelen özellik tabanlı test kütüphanesidir. Tanımladığınız özellikleri alır ve bunları zorlamak için test verileri üretme zorluğunu üstlenir. Sadece rastgele bir veri üreteci değil; hataları verimli bir şekilde bulmak için tasarlanmış zeki ve güçlü bir araçtır.
Hypothesis'in Temel Özellikleri
- Otomatik Test Durumu Oluşturma: İhtiyacınız olan verilerin *şeklini* (örneğin, "tamsayıların listesi", "yalnızca harfler içeren bir dize", "gelecekteki bir tarih-saat") tanımlarsınız ve Hypothesis bu şekle uygun çok çeşitli örnekler üretir.
- Akıllı Küçültme: Bu sihirli özelliktir. Hypothesis bir başarısız test durumu bulduğunda (örneğin, sıralama fonksiyonunuzu çökerten 50 karmaşık sayıdan oluşan bir liste), sadece o devasa listeyi rapor etmez. Başarısızlığa neden olan mümkün olan en küçük örneği bulmak için girdiyi akıllıca ve otomatik olarak basitleştirir. 50 öğeli bir liste yerine, başarısızlığın sadece
[inf, nan]
ile meydana geldiğini bildirebilir. Bu, hata ayıklamayı inanılmaz derecede hızlı ve verimli hale getirir. - Kesintisiz Entegrasyon: Hypothesis,
pytest
veunittest
gibi popüler test çerçeveleriyle mükemmel bir şekilde entegre olur. Mevcut örnek tabanlı testlerinizin yanında, iş akışınızı değiştirmeden özellik tabanlı testler ekleyebilirsiniz. - Zengin Strateji Kütüphanesi: Basit tamsayılardan ve dizelerden karmaşık, iç içe geçmiş veri yapılarından, zaman dilimi bilincine sahip tarih ve saatlere ve hatta NumPy dizilerine kadar her şeyi oluşturmak için geniş bir yerleşik "strateji" koleksiyonuyla birlikte gelir.
- Durumsal Test Etme: Daha karmaşık sistemler için Hypothesis, durum geçişlerindeki hataları bulmak için eylem dizilerini test edebilir; bu, örnek tabanlı test ile son derece zordur.
Başlarken: İlk Hypothesis Testiniz
Ellerinizi kirletelim. Hypothesis'i anlamanın en iyi yolu onu eylem halinde görmektir.
Kurulum
İlk olarak, Hypothesis'i ve tercih ettiğiniz test çalıştırıcısını (pytest
kullanacağız) yüklemeniz gerekecek. Şunun kadar basit:
pip install pytest hypothesis
Basit Bir Örnek: Bir Mutlak Değer Fonksiyonu
Bir sayının mutlak değerini hesaplaması gereken basit bir fonksiyon düşünelim. Biraz hatalı bir uygulama şöyle görünebilir:
# `my_math.py` adlı bir dosyada def custom_abs(x): """Mutlak değer fonksiyonunun özel bir uygulaması.""" if x < 0: return -x return x
Şimdi, test_my_math.py
adlı bir test dosyası yazalım. İlk olarak, geleneksel pytest
yaklaşımı:
# test_my_math.py (Örnek Tabanlı) 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
Bu testler geçer. Bu örneklere dayanarak fonksiyonumuz doğru görünüyor. Ancak şimdi, Hypothesis ile özellik tabanlı bir test yazalım. Mutlak değer fonksiyonunun temel bir özelliği nedir? Sonuç hiçbir zaman negatif olmamalıdır.
# test_my_math.py (Hypothesis ile Özellik Tabanlı) 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): """Özellik: Herhangi bir tamsayının mutlak değeri her zaman >= 0'dır.""" assert custom_abs(x) >= 0
Bunu parçalayalım:
from hypothesis import given, strategies as st
: Gerekli bileşenleri içe aktarıyoruz.given
, normal bir test fonksiyonunu özellik tabanlı bir teste dönüştüren bir dekoratördür.strategies
, veri üreticilerimizi bulduğumuz modüldür.@given(st.integers())
: Bu, testin çekirdeğidir.@given
dekoratörü, Hypothesis'e bu test fonksiyonunu birden fazla kez çalıştırmasını söyler. Her çalıştırmada, sağlanan stratejiyi,st.integers()
kullanarak bir değer üretecek ve bunu test fonksiyonumuza argümanx
olarak geçirecektir.assert custom_abs(x) >= 0
: Bu bizim özelliğimiz. Hypothesis'in hayal ettiği herhangi bir tamsayıx
için, fonksiyonumuzun sonucunun sıfırdan büyük veya ona eşit olması gerektiğini onaylıyoruz.
Bunu pytest
ile çalıştırdığınızda, büyük olasılıkla birçok değer için geçecektir. Hypothesis 0, -1, 1, büyük pozitif sayılar, büyük negatif sayılar ve daha fazlasını deneyecektir. Basit fonksiyonumuz bunların hepsini doğru bir şekilde ele alır. Şimdi, bir zayıflık bulup bulamayacağımızı görmek için farklı bir strateji deneyelim.
# Kayan noktalı sayılarla test edelim @given(st.floats()) def test_abs_floats_property(x): assert custom_abs(x) >= 0
Bunu çalıştırırsanız, Hypothesis hızla başarısız bir durum bulacaktır!
Falsifying example: test_abs_floats_property(x=nan) ... assert custom_abs(nan) >= 0 AssertionError: assert nan >= 0
Hypothesis, float('nan')
(Sayı Değil) verildiğinde fonksiyonumuzun nan
döndürdüğünü keşfetti. nan >= 0
ifadesi yanlıştır. Manuel olarak test etmeyi düşünmeyeceğimiz ince bir hata bulduk. Fonksiyonumuzu bu durumu ele almak üzere düzeltebiliriz, belki bir ValueError
yükselterek veya belirli bir değer döndürerek.
Daha da iyisi, hata çok özel bir float ile ilgiliyse ne olurdu? Hypothesis'in küçültücüsü, büyük, karmaşık bir başarısız sayıyı alıp, hatayı tetikleyen en basit versiyonuna indirecekti.
Stratejilerin Gücü: Test Verilerinizi Hazırlamak
Stratejiler, Hypothesis'in kalbidir. Veri üretme tarifleridir. Kütüphane, çok çeşitli yerleşik stratejiler içerir ve hayal edebileceğiniz hemen hemen her veri yapısını oluşturmak için bunları birleştirebilir ve özelleştirebilirsiniz.
Yaygın Yerleşik Stratejiler
- Sayısal:
st.integers(min_value=0, max_value=1000)
: İsteğe bağlı olarak belirli bir aralıkta olmak üzere tamsayılar üretir.st.floats(min_value=0.0, max_value=1.0, allow_nan=False, allow_infinity=False)
: Özel değerler üzerinde ince taneli kontrol ile kayan noktalar üretir.st.fractions()
,st.decimals()
- Metin:
st.text(min_size=1, max_size=50)
: Belirli bir uzunlukta unicode dizeleri oluşturur.st.text(alphabet='abcdef0123456789')
: Belirli bir karakter kümesinden dizeler oluşturur (örneğin, onaltılık kodlar için).st.characters()
: Tek tek karakterler oluşturur.
- Koleksiyonlar:
st.lists(st.integers(), min_size=1)
: Her öğesi bir tamsayı olan listeler oluşturur. Başka bir stratejiyi argüman olarak nasıl geçirdiğimize dikkat edin! Buna bileşim denir.st.tuples(st.text(), st.booleans())
: Sabit bir yapıya sahip demetler oluşturur.st.sets(st.integers())
st.dictionaries(keys=st.text(), values=st.integers())
: Belirtilen anahtar ve değer türlerine sahip sözlükler oluşturur.
- Zamansal:
st.dates()
,st.times()
,st.datetimes()
,st.timedeltas()
. Bunlar zaman dilimi farkında hale getirilebilir.
- Çeşitli:
st.booleans()
:True
veyaFalse
oluşturur.st.just('constant_value')
: Her zaman aynı tek değeri oluşturur. Karmaşık stratejiler oluşturmak için kullanışlıdır.st.one_of(st.integers(), st.text())
: Sağlanan stratejilerden birinden bir değer oluşturur.st.none()
: YalnızcaNone
oluşturur.
Stratejileri Birleştirmek ve Dönüştürmek
Hypothesis'in gerçek gücü, daha basit olanlardan karmaşık stratejiler oluşturma yeteneğinden gelir.
.map()
Kullanımı
.map()
yöntemi, bir stratejiden bir değer alıp başka bir şeye dönüştürmenizi sağlar. Bu, özel sınıflarınızın nesnelerini oluşturmak için mükemmeldir.
# Basit bir veri sınıfı from dataclasses import dataclass @dataclass class User: user_id: int username: str # User nesneleri oluşturmak için bir strateji 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()
.filter()
ve assume()
Kullanımı
Bazen belirli oluşturulan değerleri reddetmeniz gerekir. Örneğin, toplamı sıfır olmayan bir tamsayı listesine ihtiyacınız olabilir. .filter()
kullanabilirsiniz:
st.lists(st.integers()).filter(lambda x: sum(x) != 0)
Ancak, .filter()
kullanmak verimsiz olabilir. Koşul sık sık yanlışsa, Hypothesis geçerli bir örnek oluşturmak için uzun süre harcayabilir. Daha iyi bir yaklaşım genellikle test fonksiyonunuzun içinde assume()
kullanmaktır:
from hypothesis import assume @given(st.lists(st.integers())) def test_something_with_non_zero_sum_list(numbers): assume(sum(numbers) != 0) # ... burada test mantığınız ...
assume()
Hypothesis'e şunu söyler: "Bu koşul karşılanmazsa, bu örneği atla ve yenisini dene." Bu, test verilerinizi kısıtlamanın daha doğrudan ve genellikle daha performanslı bir yoludur.
st.composite()
Kullanımı
Gerçekten karmaşık veri oluşturma için, bir oluşturulan değerin diğerine bağlı olduğu durumlarda, st.composite()
ihtiyacınız olan araçtır. Bir argüman olarak özel bir draw
fonksiyonu alan bir fonksiyon yazmanıza izin verir; bu fonksiyonu, diğer stratejilerden adım adım değer çekmek için kullanabilirsiniz.
Klasik bir örnek, bir liste ve o liste için geçerli bir dizin oluşturmaktır.
@st.composite def list_and_index(draw): # İlk olarak, boş olmayan bir liste çekin my_list = draw(st.lists(st.integers(), min_size=1)) # Ardından, o liste için garantili geçerli bir dizin çekin 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 # Bu erişim, stratejiyi nasıl oluşturduğumuz nedeniyle garantili olarak güvenlidir element = my_list[index] assert element is not None # Basit bir ifade
Hypothesis Eylem Halinde: Gerçek Dünya Senaryoları
Bu kavramları, yazılım geliştiricilerin her gün karşılaştığı daha gerçekçi sorunlara uygulayalım.
Senaryo 1: Bir Veri Seri Hale Getirme Fonksiyonunu Test Etme
Bir kullanıcı profilini (bir sözlük) URL güvenli bir dizeye seri hale getiren ve onu seri durumdan çıkaran bir fonksiyon hayal edin. Temel bir özellik, işlemin tamamen tersine çevrilebilir olmasıdır.
import json import base64 def serialize_profile(data: dict) -> str: """Bir sözlüğü URL güvenli bir base64 dizesine seri hale getirir.""" json_string = json.dumps(data) return base64.urlsafe_b64encode(json_string.encode('utf-8')).decode('utf-8') def deserialize_profile(encoded_str: str) -> dict: """Bir dizeyi geri bir sözlüğe seri durumdan çıkarır.""" json_string = base64.urlsafe_b64decode(encoded_str.encode('utf-8')).decode('utf-8') return json.loads(json_string) # Şimdi test için # JSON uyumlu sözlükler oluşturan bir stratejiye ihtiyacımız var 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): """Özellik: Kodlanmış bir profilin seri durumdan çıkarılması, orijinal profili döndürmelidir.""" encoded = serialize_profile(profile) decoded = deserialize_profile(encoded) assert profile == decoded
Bu tek test, fonksiyonlarımızı çok çeşitli verilerle bombardımana tutacaktır: boş sözlükler, iç içe listeler içeren sözlükler, unicode karakterleri içeren sözlükler, garip anahtarlara sahip sözlükler ve daha fazlası. Birkaç manuel örnek yazmaktan çok daha kapsamlıdır.
Senaryo 2: Bir Sıralama Algoritmasını Test Etme
Sıralama örneğimizi yeniden ziyaret edelim. İşte daha önce tanımladığımız özellikleri nasıl test edeceğiniz.
from collections import Counter def my_buggy_sort(numbers): # Küçük bir hata tanıtalım: yinelenenleri düşürür return sorted(list(set(numbers))) @given(st.lists(st.integers())) def test_sorting_properties(numbers): sorted_list = my_buggy_sort(numbers) # Özellik 1: Çıktı sıralanmıştır for i in range(len(sorted_list) - 1): assert sorted_list[i] <= sorted_list[i+1] # Özellik 2: Öğeler aynıdır (bu hatayı bulacaktır) assert Counter(numbers) == Counter(sorted_list) # Özellik 3: Fonksiyon idempotenttir assert my_buggy_sort(sorted_list) == sorted_list
Bu testi çalıştırdığınızda, Hypothesis hızla Özellik 2 için numbers=[0, 0]
gibi başarısız bir örnek bulacaktır. Fonksiyonumuz [0]
döndürür ve Counter([0, 0])
, Counter([0])
'a eşit değildir. Küçültücü, başarısız örneğin mümkün olduğunca basit olmasını sağlayacak ve hatanın nedenini hemen belirgin hale getirecektir.
Senaryo 3: Durumsal Test Etme
Zamanla değişen dahili duruma sahip nesneler için (bir veritabanı bağlantısı, bir alışveriş sepeti veya bir önbellek gibi), hata bulmak inanılmaz derecede zor olabilir. Bir hatayı tetiklemek için belirli bir işlem dizisi gerekebilir. Hypothesis, tam olarak bu amaç için `RuleBasedStateMachine` sağlar.
Bellekteki bir anahtar-değer deposu için basit bir API hayal edin:
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)
Davranışını modelleyebilir ve bir durum makinesi ile test edebiliriz:
from hypothesis.stateful import RuleBasedStateMachine, rule, Bundle class KeyValueStoreMachine(RuleBasedStateMachine): def __init__(self): super().__init__() self.model = {} self.sut = SimpleKeyValueStore() # Bundle() kurallar arasında veri geçmek için kullanılır 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, key): 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() # Testi çalıştırmak için, makineden ve unittest.TestCase'den sadece alt sınıf oluşturursunuz # Pytest'te, testi sadece makine sınıfına atayabilirsiniz TestKeyValueStore = KeyValueStoreMachine.TestCase
Hypothesis, artık `set_key`, `delete_key`, `get_key` ve `check_size` işlemlerinin rastgele dizilerini yürütecek ve onaylardan birinin başarısız olmasına neden olan bir dizi bulmaya yorulmadan çalışacaktır. Silinmiş bir anahtarı almanın doğru davranıp davranmadığını, birden fazla ayarlamadan ve silmeden sonra boyutun tutarlı olup olmadığını ve manuel olarak test etmeyi düşünmeyebileceğiniz birçok farklı senaryoyu kontrol edecektir.
En İyi Uygulamalar ve Gelişmiş İpuçları
- Örnek Veritabanı: Hypothesis zekidir. Bir hata bulduğunda, başarısız örneği yerel bir dizine (
.hypothesis/
) kaydeder. Testlerinizi bir sonraki çalıştırdığınızda, ilk olarak o başarısız örneği tekrar oynatacak ve hatanın hala mevcut olduğuna dair anında geri bildirim sağlayacaktır. Onu düzelttiğinizde, örnek artık tekrarlanmaz. @settings
ile Test Yürütümünü Kontrol Etme:@settings
dekoratörünü kullanarak test çalıştırmasının birçok yönünü kontrol edebilirsiniz. Örnek sayısını artırabilir, tek bir örneğin ne kadar süreceği için bir son tarih belirleyebilirsiniz (sonsuz döngüleri yakalamak için) ve belirli sağlık kontrollerini kapatabilirsiniz.@settings(max_examples=500, deadline=1000) # 500 örnek çalıştırın, 1 saniyelik son tarih @given(...) ...
- Başarısızlıkları Yeniden Üretmek: Her Hypothesis çalıştırması bir tohum değeri yazdırır (örneğin,
@reproduce_failure('version', 'seed')
). Bir CI sunucusu yerel olarak yeniden üretemediğiniz bir hata bulursa, Hypothesis'i tam olarak aynı örnek dizisini çalıştırmaya zorlamak için bu dekoratörü sağlanan tohumla birlikte kullanabilirsiniz. - CI/CD ile Entegrasyon: Hypothesis, herhangi bir sürekli entegrasyon hattı için mükemmel bir uyumdur. Üretimden önce bilinmeyen hataları bulma yeteneği, onu paha biçilmez bir güvenlik ağı yapar.
Zihniyet Değişimi: Özellikler Üzerine Düşünmek
Hypothesis'i benimsemek, sadece yeni bir kütüphane öğrenmekten daha fazlasıdır; kodunuzun doğruluğu hakkında yeni bir düşünme biçimini benimsemektir. "Hangi girdileri test etmeliyim?" diye sormak yerine, "Bu kodla ilgili evrensel gerçekler nelerdir?" diye sormaya başlarsınız.
Özellikleri tanımlamaya çalışırken size rehberlik edecek bazı sorular şunlardır:
- Ters bir işlem var mı? (örneğin, seri hale getir/seri durumdan çıkar, şifrele/deşifre et, sıkıştır/aç). Özellik, işlemi ve tersinin gerçekleştirilmesinin orijinal girdiyi vermesidir.
- İşlem idempotent mi? (örneğin,
abs(abs(x)) == abs(x)
). Fonksiyonu birden fazla kez uygulamak, onu bir kez uygulamakla aynı sonucu vermelidir. - Aynı sonucu hesaplamanın farklı, daha basit bir yolu var mı? Karmaşık, optimize edilmiş fonksiyonunuzun basit, açıkça doğru bir sürümle (örneğin, süslü sıralamanızı Python'ın yerleşik
sorted()
fonksiyonuna karşı test etmek) aynı çıktıyı ürettiğini test edebilirsiniz. - Çıktı hakkında her zaman doğru olması gereken nedir? (örneğin, bir `find_prime_factors` fonksiyonunun çıktısı yalnızca asal sayılar içermeli ve bunların çarpımı girdiye eşit olmalıdır).
- Durum nasıl değişir? (Durumsal test için) Herhangi bir geçerli işlemden sonra hangi değişmezlerin korunması gerekir? (örneğin, bir alışveriş sepetindeki öğe sayısı asla negatif olamaz).
Sonuç: Yeni Bir Güven Seviyesi
Hypothesis ile özellik tabanlı test, örnek tabanlı testin yerini almaz. Hala kritik iş mantığı ve iyi anlaşılmış gereksinimler için belirli, elle yazılmış testlere ihtiyacınız var (örneğin, "X ülkesinden bir kullanıcı Y fiyatını görmelidir").
Hypothesis'in sağladığı şey, kodunuzun davranışını keşfetmek ve öngörülemeyen kenar durumlara karşı koruma sağlamak için güçlü, otomatik bir yöntemdir. İnsanların gerçekçi olarak yazabileceğinden daha çeşitli ve sinsi binlerce test üreten yorulmak bilmeyen bir ortaktır. Kodunuzun temel özelliklerini tanımlayarak, Hypothesis'in test edebileceği sağlam bir belirtim oluşturur, bu da size yazılımınızda yeni bir güven seviyesi sağlar.
Bir dahaki sefere bir fonksiyon yazdığınızda, örneklere bakmanın ötesine geçmek için bir an ayırın. Kendinize sorun, "Kurallar nelerdir? Nelerin her zaman doğru olması gerekir?" Ardından, Hypothesis'in onları kırma zor işini yapmasına izin verin. Ne bulduğuna şaşıracaksınız ve kodunuz bunun için daha iyi olacaktır.