Python’da alay etme: Unittest.mock, patch ve Testleri Yalan Yapan Hatalar

  1. Ana sayfa
  2. Blog
  3. Test Otomasyonu

Test Otomasyonu

Python’da alay etme: unittest.mock, patch ve Testleri Yalan Yapan Hatalar

Mocks, kodu gerçek bir ağ, veritabanı veya saat olmadan test etmenize olanak tanır. Dikkatsizce kullanıldığında bozuk kodun geçmesine de izin verirler. Unittest.mock’un her örnek çalıştırmada nasıl iyi kullanılacağı aşağıda açıklanmıştır.

8 dk okuma
Python'da alay etme: Unittest.mock, patch ve testlerin yalan söylemesine neden olan hatalar

Önemli noktalar

  • Bir sahte, API istemcisi gibi gerçek bir nesnenin yerine geçer, böylece testler hızlı ve çevrimdışı çalışır.
  • Sabit bir cevap için return_value‘i, hatalar veya sıralama için side_effect‘yi kullanın.
  • Adın tanımlandığı yeri değil, kullanıldığı yeri yamalayın. Bu en yaygın hatadır.
  • Yazım hatalarının ve yanlış argümanların sessizce iletilmesi yerine başarısız olması için spec veya autospec‘yi kullanın.

İşleviniz bir hava durumu API’sini çağırır. Testiniz internete, API anahtarına veya yarının hava durumuna bağlı olmamalıdır. Python’un yerleşik unittest.mock özelliği, bu çağrıyı tam olarak seçtiğiniz şeyi döndüren bir stand-in ile değiştirmenize olanak tanır.

Küçük bir weather modül ve dokuz test yazdık; bunların tümü Python 3.13’ün en küçük testiyle çalıştırıldı. Dokuzunun tamamı geçti ve aşağıdaki basılı çıktılar bu çalışmadan geliyor.

Neden alay edesiniz ki?

  • Hız: ağ çağrısı veya veritabanı kurulumu yok.
  • Güvenilirlik: üçüncü taraf bir hizmetin çalışmaması nedeniyle testler başarısız olmaz.
  • Kontrol: isteğe bağlı olarak zaman aşımlarını, hataları ve tek verileri simüle edebilirsiniz.
  • İzolasyon: başka birinin sunucusunu değil, kendi mantığınızı test edersiniz.

Taklitler esas olarak birim testlerine aittir. Entegrasyon testleri yine de gerçek veya gerçekçi bağımlılıklarla konuşmalıdır.

Sahte temeller

from unittest.mock import Mock

api = Mock()
api.get_price.return_value = 499

print(api.get_price("pen"))                # 499
api.get_price.assert_called_once_with("pen")
print(api.get_price.call_args_list)        # [call('pen')]
print(api.anything_at_all())               # <Mock name='mock.anything_at_all()' ...>

Bir Mock her aramayı kaydeder, böylece nasıl kullanıldığını kontrol edebilirsiniz. Ancak son satıra dikkat edin. Sade bir Mock, istediğiniz herhangi bir özelliği icat eder. Bu esneklik kullanışlıdır ve göreceğimiz gibi aynı zamanda tehlikelidir.

MagicMock aynı fikirdir ancak aynı zamanda __len__ ve __iter__ gibi “sihirli” yöntemleri de destekler. patch() varsayılan olarak MagicMock’u kullanır.

yan etki: hatalar ve diziler

side_effect her çağrıda ne olacağını kontrol eder. Bir arızayı simüle etmek için bunu bir istisnaya ayarlayın:

api.fetch.side_effect = ConnectionError("down")
api.fetch()   # raises ConnectionError

Ardışık aramalarda farklı sonuçlar döndürmek için bunu bir listeye ayarlayın. Bu, yeniden deneme mantığını test etmek için mükemmeldir:

def fetch_with_retry(api, attempts=3):
    for _ in range(attempts):
        try:
            return api.fetch()
        except ConnectionError:
            continue
    raise ConnectionError("all attempts failed")

api = Mock()
api.fetch.side_effect = [ConnectionError("busy"), {"ok": True}]
print(fetch_with_retry(api))    # {'ok': True}
print(api.fetch.call_count)     # 2

İlk çağrı başarısız oldu, ikincisi başarılı oldu ve test, işlevin tam olarak bir kez yeniden denendiğini kanıtladı. Bunu gerçek bir hizmete karşı simüle etmek neredeyse imkansız olacaktır.

patch(): bir şeyi geçici olarak değiştirin

Çoğunlukla bağımlılık aktarılmaz. Modülün içine aktarılır. patch() test süresince onu değiştirir ve daha sonra geri yükler:

# weather.py
from http_client import get as requests_get

def report(city):
    data = requests_get(f"https://api.example.com/weather?city={city}")
    return f"{city}: {data['temp_c']}°C"
from unittest.mock import patch

with patch("weather.requests_get") as fake_get:
    fake_get.return_value = {"temp_c": 31}
    print(weather.report("Pune"))   # Pune: 31°C
    fake_get.assert_called_once_with(
        "https://api.example.com/weather?city=Pune")

patch‘i bunun gibi bir içerik yöneticisi olarak veya sahteyi argüman olarak ileten bir dekoratör olarak kullanabilirsiniz.

Tanımlandığı yer değil, kullanıldığı yer yama

Bu neredeyse herkesin bir kez yaptığı hatadır. Gerçek get işlevi http_client‘de yaşıyor, bu yüzden onu oraya yamamak doğal geliyor:

with patch("http_client.get") as fake_get:
    fake_get.return_value = {"temp_c": 99}
    weather.report("Pune")

# ConnectionError: no network in tests: https://api.example.com/weather?city=Pune

Gerçek fonksiyon çalıştı. weather.py, from http_client import get as requests_get‘yi yaptığında, orijinal fonksiyona işaret ederek kendi adını yarattı. http_client.get yaması farklı bir adı değiştirdi, bu yüzden weather sahtesini hiç görmedi. Bizim http_client.get kasıtlı olarak artırıldı, dolayısıyla hata çok yüksek oldu. Gerçek bir projede sessizce canlı bir API çağırabilir.

Kural: test edilen modüldeki adı "module_under_test.name" olarak yazın. Eğer modül import http_client‘ü yaptıysa ve http_client.get()‘ü çağırıyorsa, arama sırasında gerçekleştiği için "http_client.get"‘in yamalanması doğrudur.

spec ve autospec: taklitleri katı hale getirin

Sade bir Mock, yazım hataları dahil her şeyi kabul eder. Bir spesifikasyonla yalnızca gerçek sınıfın sahip olduğu niteliklere izin verilir:

api = Mock(spec=weather.WeatherClient)
api.get_temprature("Pune")
# AttributeError: Mock object has no attribute 'get_temprature'

loose = Mock()
loose.get_temprature("Pune")    # returns a Mock, no error at all

Gevşek sahte, yanlış yazım yöntemini memnuniyetle kabul etti, böylece onu kullanan bir test, gerçek kod çökse bile başarılı olabilir. autospec daha da ileri giderek yöntem imzalarını kontrol eder:

with patch("weather.WeatherClient", autospec=True) as Fake:
    client = Fake.return_value
    client.get_temperature("Pune", "extra", "args")
# TypeError: too many positional arguments

Kendi sınıflarınızla alay ederken autospec=True veya create_autospec()‘yi tercih edin. Gerçek kod değiştikçe alayların dürüst olmasını sağlar.

Tarih ve saatlerle alay etmek

Bugünün tarihine bağlı olan kodun test edilmesi zordur. Saati küçük bir işleve sarın ve şunu ekleyin:

def today():
    return datetime.date.today()

def is_weekend():
    return today().weekday() >= 5

@patch("weather.today")
def test_date(self, fake_today):
    fake_today.return_value = datetime.date(2026, 11, 7)
    print(weather.is_weekend())   # True (a Saturday)

Yerleşik türler özniteliklerinin ayarlanmasına izin vermediğinden datetime.date.today‘e doğrudan yama uygulayamazsınız. Freegun ve time machine gibi kütüphaneler bunu daha kapsamlı bir şekilde ele alıyor.

Alaylarla ilgili iddialar

Yöntem Çekler
assert_called() En az bir kez aradı
assert_called_once() Tam olarak bir kez aradı
assert_called_with(...) Son çağrıda bu argümanlar kullanıldı
assert_called_once_with(...) Bu argümanlarla tam olarak bir çağrı
assert_any_call(...) Bu bağımsız değişkenleri kullanan herhangi bir çağrı
assert_not_called() Hiç aramadım

Bir iddia başarısız olduğunda mesaj açıktır. Hiçbir zaman çalışmayan bir yöntem üzerinde assert_called_once()‘i çağırdık:

AssertionError: Expected 'save' to have been called once. Called 0 times.

Daha eski Python sürümleri, assret_called_once gibi yanlış yazılmış onaylama yöntemlerinin sessizce geçmesine izin verir. Modern versiyonlar, assert ile başlayan isimlerde veya bunun yaygın yazım hatalarında hataya neden olur, ancak spesifikasyon hala daha güçlü bir korumadır.

pytest ve alaylar

Yukarıdaki her şey pytest’te de çalışıyor. Pek çok pytest kullanıcısı, basit değiştirmeler için yerleşik monkeypatch fikstürünü veya yamaları otomatik olarak geri alan bir mocker fikstürü sağlayan pytest-mock eklentisini de kullanır. Hepsi için “kullanıldığı yerdeki yama” kuralı geçerlidir. Fikstürler ve kurulum için pytest eğitimimize bakın.

Ne zaman alay edilmemeli

  • Test ettiğiniz şeyle alay etmeyin. Eğer taklit tüm işi yaparsa, test hiçbir şeyi kanıtlamaz.
  • Basit değer nesneleriyle alay etmekten kaçının. Gerçeği kullanın.
  • Her şeyle alay etmeyin. Alaylarla dolu testler, davranış doğru olsa bile kod yeniden düzenlendiğinde sıklıkla bozulur.
  • Bazı gerçek entegrasyon testleri yapın. Mock’lar, bir hizmetle ilgili varsayımlarınızı kodlar ve bu varsayımlar yanlış olabilir.

Sahte yollar, arkalarında herhangi bir gerçek davranış olmadan çalıştığından, sahte yollar kod kapsamını da kolaylıkla genişletir.

Yaygın alay hataları

  • Yanlış adın yamalanması. Yukarıda ele alındı ve hâlâ “taklitlerim göz ardı ediliyor”un bir numaralı nedeni.
  • Dönüş_değerini ayarlamayı unutmak. Test edilen kod daha sonra veri yerine bir Mock nesnesi alır. Örneğin, yalnızca bir sonucun doğru olup olmadığını kontrol ettiğinizde, işlevinizden doğrudan geçebilir ve kazara bir test geçişi yapabilir.
  • Sonuç yerine sahte iddiada bulunmak. save()‘nin çağrıldığını kontrol etmek, neyin kaydedildiğini kontrol etmekten daha zayıftır. assert_called_once_with(...)‘ü gerçek argümanlarla kullanın veya daha iyisi fonksiyonun sonucunu iddia edin.
  • Yamaları sızdırıyor. stop() olmadan patcher.start()‘yi çağırmak, sahteyi daha sonraki testler için yerinde bırakır. İçerik yöneticisini, dekoratörü veya addCleanup(patcher.stop)‘ü kullanın.
  • Yığılmış dekoratörler yanlış sırada. Birkaç @patch dekoratörde, en alttaki ilk argüman olarak iletilir. Bunları sessizce karıştırmak yanlış modeli yapılandırır.
  • Birçok testte sahip olmadığınız bir kitaplıkla alay etmek. Bunu kendinize ait küçük bir sınıfa sarın ve bunun yerine bununla dalga geçin. Testleriniz daha sonra kütüphanenin API’sini değil ihtiyaçlarınızı açıklar.

Alaylar, taslaklar ve sahteler

Bu kelimeler genellikle gevşek bir şekilde kullanılır, ancak farklılıklar testleri tartışırken yardımcı olur. Bir taslak yalnızca hazır yanıtları döndürür. Bir sahte ayrıca, nasıl kullanıldığını doğrulayabilmeniz için çağrıları da kaydeder. Sahte, veritabanı yerine bellek içi depo gibi çalışan, basitleştirilmiş bir uygulamadır. Python’un Mock saplama veya taklit görevi görebilir. Sahteler, kendi yazdığınız sıradan sınıflardır ve genellikle yeniden düzenlemede daha iyi hayatta kalan testlere yol açarlar çünkü kesin çağrılardan ziyade davranışı kontrol ederler.

İyi bir genel kural, sisteminizin kenarlarıyla alay etmektir: ağ, saat, rastgele sayılar, dosya sistemi ve ücretli üçüncü taraf hizmetler. Bu kenarların içinde gerçek nesneleri tercih edin. Bu şekilde oluşturulan testler hızlı kalır ve gerçekte yazdığınız kodu kullanmaya devam eder.

Son sözler

Alay etmek hassas bir araçtır: yavaş veya öngörülemeyen bağımlılıkları değiştirin, ne döndürdüklerini kontrol edin ve kodunuzun bunları nasıl kullandığını kontrol edin. İki alışkanlık çoğu sorunu önler. Test edilen modüldeki adı yamalayın ve otomatik belirtimi kullanın, böylece taklitleriniz gerçek nesnenin reddedeceği çağrıları reddeder.

Sık sorulan sorular

Python’da alay etmek nedir?

Mocking, API istemcisi veya veritabanı gibi gerçek bir nesneyi, test sırasında kontrol ettiğiniz sahte bir nesneyle değiştirir. Python bunu Unittest.mock modülüne dahil eder.

Mock ve MagicMock arasındaki fark nedir?

MagicMock, __len__, __iter__ ve __enter__ gibi sihirli yöntemleri de destekleyen bir Mock’tur. patch() varsayılan olarak bir MagicMock oluşturur.

Yamam neden çalışmıyor?

Genellikle nesnenin kullanıldığı yer yerine tanımlandığı yeri yamaladığınız için. Test edilen modülün içindeki adı yamalayın.

dönüş_değeri ile yan_etki arasındaki fark nedir?

return_value sabit bir sonuç ayarlar. side_fect bir istisna oluşturabilir, listeden değerleri sırayla döndürebilir veya bir işlevi çağırabilir.

Autospec ne işe yarar?

Gerçek nesneden bir örnek oluşturur, bu nedenle eksik özellikler ve yanlış argümanlar, tıpkı gerçek kodda olduğu gibi hatalara neden olur.

Öğrenmeye devam et

Stack Quora ile çalışın

Test, WordPress veya SEO konusunda yardıma mı ihtiyacınız var?

Ekiplerin daha iyi yazılımlar sunmasına ve sitelerini büyütmesine yardımcı oluyoruz. Bize ne üzerinde çalıştığınızı söyleyin, biz de bir sonraki adım için net bir öneride bulunalım.

Okumaya devam et

Daha fazla kılavuz test, yapay zeka ve modern geliştirme

Bu makaleyi beğendiniz mi? Bir konu seçin ve doğrudan en yeni eğitimlerimize geçin.

Yapay zekâ

Yapay Zeka Halüsinasyonları Açıklandı: Dil Modelleri Neden İşleri Düzeltiyor ve Nasıl Azaltılabilir?

Yapay zeka halüsinasyonları açıkladı: ne olduklarını, dil modellerinin bunları neden ürettiğini, yaygın türlerini, temellendirme ve yönlendirmelerle…

Makaleyi okuyun →
DevOps

Açıklanan Ortam Değişkenleri: .env Dosyaları, Sırlar ve Yapılandırma Doğru Yapıldı

Çalıştırdığımız Python örnekleriyle açıklanan ortam değişkenleri: bunları okumak ve ayarlamak, neden her değerin bir dize olduğu, .env dosyaları, sü…

Makaleyi okuyun →
Yazılım geliştirme

API Hız Sınırlamasının Açıklaması: Algoritmalar, Başlıklar ve 429 Hatalarının Ele Alınması

API hızı sınırlaması, çalıştırdığımız bir simülasyonla açıklanmıştır: belirteç kümesi, sabit pencere, kayan pencere, 429 yanıt, hız sınırı başlıklar…

Makaleyi okuyun →
Test otomasyonu

Python'da alay etme: Unittest.mock, patch ve Testleri Yalan Yapan Hatalar

Unittest.mock ile Python'da alay etme, test edildi: Sahte ve dönüş_değeri, yan_etki, bir adın kullanıldığı yerde yama uygulama, spesifikasyon ve oto…

Makaleyi okuyun →
Yazılım testi

Kod Kapsamının Açıklaması: Hat ve Şube Kapsamı ve %100'ün Gerçek Anlamı

Kod kapsamı gerçek bir kapsama.py çalışmasıyla açıklanmıştır: hat, şube ve durum kapsamı, bir raporun okunması, %100 kapsamın neden hâlâ hataları ka…

Makaleyi okuyun →
Veritabanları ve SQL

SQL'de DELETE vs TRUNCATE vs DROP: Farklılıklar, Geri Alma ve Her Biri Ne Zaman Kullanılmalı

DELETE vs TRUNCATE vs DROP test edilmiş SQL ile açıklandı: her birinin neyi kaldırdığı, geri aldığı, tetiklediği, kimlik sıfırlaması, hızı ve Postgr…

Makaleyi okuyun →
Veritabanları ve SQL

Açıklanan SQL Görünümleri: Örneklerle Tuzakları Oluşturun, Kullanın ve Önleyin

Çalıştırdığımız sorgularla açıklanan SQL görünümleri: görünüm oluşturma, canlı sonuçlar, sütunları gizleme, performans, güncellenebilir ve gerçekleş…

Makaleyi okuyun →
Yazılım geliştirme

TypeScript Arayüzü ve Tür: Gerçek Farklılıklar, Derleyiciyle Test Edildi

TypeScript arayüzü ve türü, gerçek derleyiciyle kontrol edildi: her ikisinin de yapabileceği, yalnızca birinin yapabileceği, bildirim birleştirme, g…

Makaleyi okuyun →
Yazılım geliştirme

Python *args ve **kwargs'ın Açıklaması: Açık Örneklerle Esnek Fonksiyonlar

Python *args ve **kwargs çalıştırdığımız kodla açıklanmıştır: paketleme ve paketten çıkarma, parametre sırası, yalnızca anahtar kelime ve yalnızca k…

Makaleyi okuyun →
Yazılım geliştirme

Python Lambda İşlevleri: Söz Dizimi, Gerçek Kullanımlar ve Ne Zaman Kullanılmaması Gerektiği

Çalıştırdığımız kodla açıklanan Python lambda işlevleri: sözdizimi, anahtarla sıralama, harita ve filtre, kapatmalar, geç bağlama tuzağı ve normal b…

Makaleyi okuyun →
Yapay zekâ

Yapay Zeka Ajanları Nelerdir? Çalıştırabileceğiniz Basit Bir Aracı Döngüsüyle Nasıl Çalışırlar?

Yapay zeka ajanları nedir? Aracı döngüsüne, araçlara, belleğe ve korkuluklara ilişkin basit bir kılavuz, çalıştırdığımız küçük bir Python döngüsü, g…

Makaleyi okuyun →
DevOps

İzleme ve Gözlemlenebilirlik: Günlükler, Metrikler ve İzlerle Gerçek Fark

İzleme ve gözlemlenebilirliğin açıklanması: bilinen ve bilinmeyen arızalar, günlükler, ölçümler ve izler, ödeme olayının gözden geçirilmesi, altın s…

Makaleyi okuyun →
DevOps

Docker Birimleri ve Bağlama Bağlantıları: Konteyner Verilerini Doğru Şekilde Kalıcılaştırın

Docker birimleri ile bağlama bağlamaları arasındaki karşılaştırma açıklandı: kapsayıcı verilerinin neden kaybolduğu, adlandırılmış birimler, bağlama…

Makaleyi okuyun →
Test otomasyonu

TDD ve BDD: Temel Farklılıklar, Her İki Şekilde Geliştirilmiş Bir Özellik ve Her Birinin Ne Zaman Kullanılacağı

TDD ve BDD, her iki yönde de oluşturulmuş bir indirim özelliğiyle açıklandı: çalıştırdığımız kodla kırmızı-yeşil-refactor, Verilen-Ne Zaman-O Zaman …

Makaleyi okuyun →
Yazılım geliştirme

Git merge vs rebase: farklar, örnekler ve hangisi ne zaman kullanılır

Git merge vs rebase; gerçek log çıktısı, karşılaştırma tablosu, rebase'in altın kuralı ve güvenli bir ekip iş akışıyla anlatılıyor.

Makaleyi okuyun →
Yazılım geliştirme

Python Liste Üreteci (List Comprehension): Sözdizimi, Örnekler ve Kaçınılacak Durumlar

Python list comprehension anlatımı: sözdizimi, filtreleme, if-else, iç içe döngüler, ölçülmüş süreler ve düz for döngüsünün daha iyi olduğu durumlar.

Makaleyi okuyun →
Veritabanları ve SQL

SQL JOIN Örneklerle Açıklama (Inner, Left, Right, Full)

SQL JOIN'leri örnek tablolar ve sorgularla adım adım öğrenin: INNER, LEFT, RIGHT, FULL, CROSS ve SELF; yaygın hatalar ve performans ipuçları.

Makaleyi okuyun →