Yan yana
MockingvsTest Stub
Mock ile stub arasındaki fark nedir?
Güncellendi 3 dk okuma7 fark
Kısaca
Stub, test edilen kod çalışabilsin diye hazır yanıtlar döndürür; mock ise nasıl çağrıldığını da denetler ve beklenen çağrılar olmazsa test başarısız olur.
Mocking
Mocking, kodu yalıtılmış biçimde test etmek için veritabanı ya da API gibi gerçek bir bağımlılığı kontrol ettiğiniz bir sahteyle değiştiren test tekniğidir.
Mocking sayfasını okuTest Stub
Test stub, gerçek bir bağımlılığın yerine geçip test sırasında hazır yanıtlar döndüren nesnedir; böylece kod gerçek veritabanı veya servis olmadan test edilir.
Test Stub sayfasını okuMocking ve Test Stub karşılaştırması
| Özellik | Mocking | Test Stub |
|---|---|---|
| Amacı | Kodun doğru çağrıları yaptığını denetler | Kodun çalışması için gereken veriyi sağlar |
| Testin doğruladığı | Mock'a yapılan çağrılar: hangileri, kaç kez, hangi argümanlarla | Test edilen kodun sonucu ya da durumu |
| Doğrulama biçimi | Davranış doğrulama (behavior verification) | Durum doğrulama (state verification) |
| Testi başarısız kılabilir mi | Evet; beklenen çağrılar eksik ya da yanlışsa | Hayır; yalnızca yanıt döndürür |
| Uygulamaya bağlılık | Daha yüksek: kodun çalışma biçimini değiştirmek testi bozabilir | Daha düşük: yalnızca sonuç denetlenir |
| Tipik kullanım | Yan etkili komutlar: e-posta göndermek, karttan ödeme almak, olay yayımlamak | Sorgular: bir döviz kuru, bir kullanıcı kaydı, güncel tarih, bir hata |
| Kütüphanelerde | Jest'te toHaveBeenCalledWith, Mockito'da verify(...) | Jest'te mockReturnValue, Mockito'da when(...).thenReturn(...) |
Fark, açıklamalı
Mock ve stub, ikisi de test double'dır: veritabanı, ödeme API'si ya da sistem saati gibi gerçek bir bağımlılığın yerine geçen ve testi hızlı ve öngörülebilir kılan vekillerdir. Stub yalnızca yanıt sağlar: kod bir döviz kuru istediğinde 0,9 döndürür, test de ardından kodun bu değerle ne yaptığını kontrol eder. Mock da yanıtlarla programlanır, ama ayrıca çağrılarını kaydeder ve onlara dair beklentiler taşır; örneğin sendEmail metodunun doğru adresle bir kez çağrılması gibi.
Asıl fark, testin neyi doğruladığıdır. Stub kullanıldığında test, test edilen kodun sonucunu ya da durumunu doğrular; Martin Fowler buna durum doğrulama (state verification) der ve stub tek başına bir testi asla başarısız kılmaz. Mock kullanıldığında ise test etkileşimin kendisini doğrular; Fowler buna davranış doğrulama (behavior verification) der ve e-posta göndermek ya da bir karttan ödeme almak gibi sonucu bir çağrı olan durumları denetlemenin tek yolu budur. Bugün en çok kullanılan terimler Gerard Meszaros'un 2007 tarihli xUnit Test Patterns kitabından gelir; kitap beş tür test double tanımlar: dummy, stub, spy, mock ve fake.
Çoğu test paketi ikisini birlikte kullanır, kütüphaneler de adları bulanıklaştırır. Jest, Sinon, Mockito ve Python'ın unittest.mock modülü, ikisi gibi de davranabilen nesneler oluşturur: mockReturnValue ya da when(...).thenReturn(...) bir stub oluşturur, toHaveBeenCalledWith ya da verify(...) ile doğrulama yapmak ise onu bir mock'a dönüştürür. Yaygın bir kalıp, kodun ihtiyaç duyduğu sorguları stub'lamak ve yalnızca çağrılması testin asıl konusu olan tek bir komutu mock'lamaktır.
Sık yapılan bir yanlış, her sahte nesnenin bir mock olduğu düşüncesidir. Her şeye mock demek asıl önemli seçimi gizler: çağrıları denetlemek testi kodun nasıl çalıştığına bağlar; bu yüzden davranış değişmese bile uygulama değiştiğinde test bozulur. Yalnızca sonuç önemliyse stub'ları tercih edin, mock'ları ise kendisi bir gereksinim olan etkileşimlere saklayın.
Hangisini kullanmalısınız?
Mocking şu durumlarda doğru seçim:
- Önemsediğiniz sonuç, e-posta göndermek gibi başka bir sisteme yapılan bir çağrı.
- Denetlenecek bir dönüş değeri ya da durum yok, yalnızca bir yan etki var.
- Bir şeyin olmadığını kanıtlamanız gerekiyor; örneğin bir karttan iki kez ödeme alınmadığını.
Test Stub şu durumlarda doğru seçim:
- Test edilen kod yavaş, maliyetli ya da güvenilmez bir bağımlılıktan veri istiyor.
- Bir hata, bir zaman aşımı ya da boş bir liste gibi belirli bir yanıtı taklit etmek istiyorsunuz.
- Yalnızca sonuç önemli ve test yeniden düzenlemelerden (refactoring) sağ çıkmalı.
Aynı Jest araçları, bir kez mock, bir kez stub olarak
// Mock: the test checks how the dependency was called
test("sends a welcome email", async () => {
const mailer = { send: jest.fn() };
await registerUser({ email: "ada@example.com" }, mailer);
expect(mailer.send).toHaveBeenCalledTimes(1);
expect(mailer.send).toHaveBeenCalledWith("ada@example.com", "Welcome!");
});// Stub: the dependency only returns a canned answer
test("converts dollars to euros", () => {
const rates = { getRate: jest.fn().mockReturnValue(0.9) };
const result = toEuros(100, rates);
expect(result).toBe(90); // the test checks the result, not the calls
});Sık sorulan sorular
Stub bir mock türü müdür?
İkisi de testlerde kullanılan her türlü vekil için genel terim olan test double'ın türleridir. Birçok kütüphane her double'a mock der; ama kesin anlamıyla stub yalnızca yanıt döndürür, mock ise çağrılarını da doğrular.
Mock ile spy arasındaki fark nedir?
Spy nasıl çağrıldığını kaydeder ve test bu çağrıları sonradan denetler; klasik bir mock ise önceden beklentilerle kurulur ve onları kendisi doğrular. Jest'te ve Sinon'da ikisi neredeyse aynıdır; jest.spyOn ayrıca gerçek bir metodu, çalışmaya devam edecek şekilde sarabilir.
Mock mu kullanmalıyım, stub mı?
Stub'larla başlayın ve sonuçları doğrulayın; böyle testler yeniden düzenlemelerden sağ çıkar. Gönderilmesi gereken bir e-posta gibi çağrının kendisi gereksinim olduğunda mock kullanın ve kodun yalnızca iç adımları olan çağrıları denetlemekten kaçının.