Test Piramidi, JUnit 5 ve Mockito
30 saniyede özet
Test piramidi güzel bir çizim değil, bir hız ve maliyet hesabı: altta çok sayıda hızlı test, üstte az sayıda yavaş test. Doğru soru şu: bu hatayı görebilecek en ucuz test hangisi?
Test piramidi genellikle güzel bir üçgen olarak çizilir. Ama asıl sebebi çok daha somut: maliyet ve cevabı ne kadar bekleyeceğin.
-
Bayt: Bütün testlerimizi tarayıcıda, gerçek kullanıcı gibi yazdık. Her şey kapsanıyor!
-
Sen: Süper. Bir satır değiştirince ne kadar bekliyorsun?
-
Bayt: Yirmi dakika... Bazen de sebepsiz kırmızı yanıyor.
-
Bayt: Gevşek bir vida için her seferinde pistte tur atmak mantıklı mı?
Adım adım oku
- Birim testi parçayı tezgâhta tek başına sınar; çok hızlıdır ve çok sayıda yazılır.
- Entegrasyon testi parçaları birlikte çalıştırır; birim testinin göremediği bağlantı hatalarını yakalar.
- Uçtan uca test arabayı pistte sürer; en gerçekçi olanıdır ama yavaştır ve bazen sebepsiz kırılır.
- Piramit bunun sonucudur: altta çok sayıda ucuz test, üstte az sayıda pahalı test.
| Katman | Tipik süre | Neyi görür | Kırılganlık |
|---|---|---|---|
| Birim | ~5 ms | Saf mantık | Yok |
| Entegrasyon | ~250 ms | Bağlantı, sözleşme, SQL | Düşük |
| Uçtan uca | ~4 sn | Tüm kullanıcı akışı | Yüksek |
Bir uçtan uca test, bir birim testinin yaklaşık 800 katı sürer. Piramidin sebebi budur.
Kendin ölç
Simülatör bir değişikliğe karşı suite’i alttan üste çalıştırıyor ve ilk gerçek hatada duruyor. İzlenecek sayı: geri bildirim süresi.
Test piramidi — hatayı ne kadar sürede duyarsın
Tohum 7Şu an ne oldu?
Birim testi — 0/200 · 0.0 sn
Bu katmanın bu hata için kapsaması %100. Test başına maliyet 5 ms.
Aklında kalsın: Piramit bir estetik tercih değil, geri bildirim süresi optimizasyonudur.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
Karşılaştır:
Piramit+Hesaplama hatası— birim katmanı saniyenin altında yakalıyor.Dondurma külahı+ aynı hata. 20 birim testi bu hatayı kaçırıyor; aynı hata dakikalar sonra, çok daha pahalı bir katmanda ortaya çıkıyor. Kaçırma sebebi birim testlerinin zayıf olması değil, yeterince olmaması.Piramit+Bean/transaction bağlantı hatası— birim katmanı bunu hiç göremiyor. Bu bir eksiklik değil, mock’un tanımı.Dondurma külahı+Kullanıcı akışı— flakyKod değişmediği hâlde bazen geçen bazen kalan test. Verdiği bilgiyi yok eder: artık "geçti" ne anlama geliyor bilmezsin.Sebebi neredeyse her zaman üç şeyden biridir: paylaşılan durum, zamanlama (sabit bekleme), ya da test sırası bağımlılığı. Retry eklemek semptomu gizler ve bazen üründeki gerçek bir yarış durumunu örter.Sözlükte gör → başarısızlıklara dikkat et. Bunlar gerçek hata değil ama zaman ve dikkat harcatıyor.
Testi "birim testi" yapan şey nedir?
Hangi katman neyi görür?
Servis birim testi repository'yi mock'luyor. Repository'deki JPQL sorgusunda bir alan adı yanlış yazılmış. Bu birim testi hatayı yakalar mı? Cevabı göster
Hayır. Mock gerçek sorguyu hiç çalıştırmaz. Bu hatayı yalnızca gerçek veritabanıyla koşan bir entegrasyon testi görür.
Bu tablo, “her şeyi birim test et” tavsiyesinin neden yanlış olduğunu gösterir:
| Hata türü | Birim | Entegrasyon | Uçtan uca |
|---|---|---|---|
| Hesaplama hatası | ✓ | ✓ | ✓ |
| Bean/transaction bağlantısı | ✕ | ✓ | ✓ |
| API sözleşmesi bozuldu | ✕ | ✓ | ✓ |
| Kullanıcı akışı kırıldı | ✕ | ✕ | ✓ |
Birim testi bağımlılıkları taklit eder — taklit ettiğin şeydeki bir hata birim testinde asla görünmez. Mock kullanmanın bedeli budur ve entegrasyon katmanının vazgeçilmez olmasının sebebi de.
Kafam karıştı, daha basit anlat
Birim testi taklit bir ortakla çalışır. Taklit gerçeğinden farklı davranıyorsa, birim testi bu farkı asla göremez. Bu yüzden birkaç gerçek entegrasyon testi de gerekir.
Test piramidinin tersi olan "ice cream cone" hangi belirtileri üretir?
Taklitler: mock, stub, spy, fake
Dördü farklı işler yapar ve sık karıştırılır:
| Tür | Ne yapar | Ne zaman |
|---|---|---|
| Stub | Sabit cevap döner | Girdi gerekiyor, davranış önemli değil |
| Mock | Nasıl çağrıldığını doğrular | Etkileşimin kendisi test konusu |
| Spy | Gerçek nesneyi sarar, bazı metotları izler/değiştirir | Legacy kodda kısmi taklit |
| Fake | Basit ama çalışan bir uygulama | In-memory repository gibi |
when(priceRepository.findBySku("A1")).thenReturn(new Price(100)); // cevabı kurorderService.place(order);verify(emailSender).send(argThat(mail -> mail.to().equals("ali@example.com")));Ayrım şu: fakeGerçeğinin basitleştirilmiş ama çalışan bir uygulaması — bellek içi bir repository gibi. Stub hazır cevap döner, mock ayrıca çağrıldığını doğrular.Sözlükte gör → girdi sağlar, mock çıktıyı doğrular. Mockito’da ikisi de mock() ile üretilir; farkı yaratan when mi yoksa verify mi yazdığındır.
Bu taklitler bir bankada da hep yan yana durur. Yurt dışı kart harcamasını TL’ye çevirip hesaptan düşen küçük bir serviste hangisinin nerede durduğuna bak.
Derinleş · Yurt dışı kart harcaması: stub, fake ve mock bir arada 4 dosya · ~109 satır · ilk okumada atlayabilirsin
Kafam karıştı, daha basit anlat
Stub hazır cevap verir, mock kendisine ne sorulduğunu kontrol eder. Spy gerçek nesneyi izler, fake ise basit ama çalışan bir kopyadır.
Mock, stub ve fake arasındaki fark nedir?
JUnit 5’te bilmeye değer birkaç şey.
@Test@DisplayName("stok yetersizse sipariş reddedilir")void rejectsWhenOutOfStock() { var exception = assertThrows(OutOfStockException.class, () -> orderService.place(order));
assertThat(exception.getMessage()).contains("SKU-1");}
@ParameterizedTest@CsvSource({ "0, false", "1, true", "99, true" })void availability(int stock, boolean expected) { assertThat(inventory.isAvailable(stock)).isEqualTo(expected);}JUnit 4’ten gelen iki değişiklik sık sorulur: @Before yerine @BeforeEach, ve @RunWith yerine @ExtendWith (Mockito için @ExtendWith(MockitoExtension.class)).
Her ifadeyi doğru test çifti türüne yerleştir.
Tuzaklar: kırılgan test, testsizlikten kötüdür
Simülatörde uçtan uca katmanın ürettiği kırılgan başarısızlıklara bak. Bir test bazen kırmızı bazen yeşilse:
- Ekip onu ciddiye almayı bırakır
- “Tekrar çalıştır” refleksi oluşur
- Ve gerçek bir hata geldiğinde de tekrar çalıştırılır
Kırılgan bir testi tamir et ya da sil. Kırmızı kalmasına izin vermek, bütün suite’e olan güveni aşındırır.
Ne test edilmeli. Pratik bir filtre: test, kodun bir şey yapmasını değil, bir şeyi yanlış yapmamasını garanti etmeli.
- Test et: iş kuralları, sınır değerler, hata yolları, düzelttiğin her hata
- Test etme: getter/setter, framework’ün kendi davranışı, kendi mock’ladığın şey
Bir hata bildirimi geldiğinde önce onu yeniden üreten kırmızı testi yazmak neredeyse her zaman doğrudur: hem düzelttiğini kanıtlar hem geri gelmesini engeller.
Kendini sına
Birim testi, mock'ladığın bağımlılıktaki bir hatayı yakalayabilir.
Test piramidinin asıl gerekçesi nedir?
Aklında kalacak üç şey
- 1 Piramidin sebebi maliyet ve bekleme süresidir. Bir uçtan uca test, bir birim testinden yaklaşık 800 kat uzun sürer ve daha kolay bozulur.
- 2 Doğru soru 'her şeyi birim test et' değil, 'bu hatayı görebilecek en ucuz katman hangisi?'. Bağlantı hatasını birim testi zaten göremez.
- 3 Mock'un bedeli: taklit ettiğin şeyin gerçekten öyle davrandığını test etmemiş olursun. Entegrasyon testleri bu yüzden vazgeçilmezdir.
5 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.
- DevOps & TestSpring Test Dilimleri ve Context CacheTek bir controller'ı test etmek için neden bütün uygulamayı ayağa kaldırasın?Derse git
- DevOps & TestSözleşme Testleri — Karşı Servis Değişince Kim Kırılır?Senin testlerinin hepsi yeşil ve kodunu hiç değiştirmedin. Peki havale ekranı neden bu sabah çöktü?Derse git
- DevOps & TestKararsız Testler — Kod Değişmedi, Test Neden Bir Kırmızı Bir Yeşil?CI kırmızı yandı. 'Tekrar çalıştır'a bastın, yeşil oldu. Bir şey düzeldi mi?Derse git