İçeriğe geç

Kararsız Testler — Kod Değişmedi, Test Neden Bir Kırmızı Bir Yeşil?

Orta 9 dk Sık karşılaşılır

Önce şunu oku: Test Piramidi, JUnit 5 ve Mockito

30 saniyede özet

Aynı kodla bazen geçen bazen kırılan test, ekibin testlere olan güvenini yer. Sebep neredeyse her zaman dört yerden biridir: saat, sıra, paylaşılan durum, beklemek. Tekrar deneme kırmızıyı gizler; sebebi bulup kapatmak gerekir.

Bir kafede oturuyorsun ve masa arada bir sallanıyor. Altına katlanmış bir peçete koyarsın, sallanma durur. Ama yarın başka biri aynı masaya oturduğunda kısa ayak hâlâ orada olacak.

  1. Bayt: CI kırmızı. Ama bu sabah hiçbir şeye dokunmadım!

  2. Sen: 'Tekrar çalıştır'a bas. Geçer.

  3. Bayt: Geçti! Tamam, birleştiriyorum.

  4. Bayt: Ama dün de böyle olmuştu. Testlerimiz bize artık doğruyu söylemiyor olabilir mi?

Neden bazen kırılır?

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 →, aynı kodla bazen geçen bazen kırılan testtir. Kod değişmediyse, değişen şey testin dışarıdan aldığı bir şeydir.

En sık dört şey: o anki saat, garanti edilmeyen bir sıra (örneğin HashSet), başka bir testin bıraktığı durum ve “100 milisaniye yeter” diye konan bir bekleme.

Kafam karıştı, daha basit anlat

Kod değişmediyse, testin dışarıdan aldığı bir şey değişmiştir: saat, sıra, başka testin bıraktığı durum ya da bekleme süresi.

Hızlı kontrolBaşlangıç

Kararsız (flaky) test nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kod değişmediği hâlde test kırıldıysa ne değişmiş olabilir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Her sebebin kendi ilacı

CI'da kırılan testleri bir kez otomatik tekrar deneyen bir ayar açtık. On koşunun hepsi yeşil. Testler artık güvenilir mi? Cevabı göster

Hayır. Sebeplerin hiçbiri değişmedi; yalnızca kırmızıyı artık görmüyorsun. Aynı ayar, ara sıra ortaya çıkan gerçek bir hatayı da yeşile çevirir.

Sebebi bul, ayağı düzelt.
Adım adım oku
  1. Masa bazen sallanıyor, bazen sallanmıyor.
  2. Altına peçete: bugünlük durdu.
  3. Ama kısa ayak hâlâ orada.
  4. Sebebi bul, ayağı düzelt.

Saati koda bir Clock olarak ver; testte sabit bir saat kullan. Sırası garanti olmayan bir koleksiyonu sırasız karşılaştır.

Her teste taze bir durum ver; buna test yalıtımıHer testin kendi taze durumuyla başlaması; bir testin sonucu başka bir testin bıraktığı veriye ya da çalışma sırasına bağlı olmaz.Sözlükte gör → denir. Asenkron işi sabit süre bekleme; koşul gerçekleşene kadar kısa aralıklarla sor.

Kafam karıştı, daha basit anlat

Sabit saat, sırasız karşılaştırma, her teste taze durum, süre yerine koşul.

Hızlı kontrolOrta

LocalDate.now() kullanan bir test gece yarısı kırılıyor. En iyi çözüm nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Asenkron bir işin bitmesini beklemek için hangisi doğrudur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Aynı kod, on CI koşusu

Tohum 678486
12345678910
faizBugünHesaplanır
hesapListesiDöner
havaleKaydedilir
ekstreGönderilir
ibanDoğrulanır

✕ kırmızı koşu: 0/0 · ↻ gizlenen kırılma: 0 · ✓ geçti, ✕ kırıldı, ↻ tekrar denemede geçti

Hız
Adım 0

Şu an ne oldu?

Kod hiç değişmiyor

Aynı test seti 10 kez koşuyor. Kırmızı her koşu, düzeltilmemiş bir sebebi gösterir.

Görevler0/3

  • Bütün koşular yeşil olsun ama hiçbir sebep düzelmesinaçık

    İpucu

    Tekrar deneme.

  • Yalnızca 7. koşu kırmızı kalsınaçık

    İpucu

    Saat dışındaki her şeyi düzelt.

  • Tekrar deneme olmadan on koşunun hepsi yeşil olsunaçık

    İpucu

    Dört sebebi de kapat.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. Kod hiç değişmeden on koşudan sekizi kırmızı. Hangi testin hangi koşuda kırıldığına bak.
  2. Yalnızca “tekrar dene”yi aç. On koşunun hepsi yeşil, ama sekiz kırılma gizlendi.
  3. Tekrar denemeyi kapat, saat dışında her şeyi düzelt. Yalnızca 7. koşu kırmızı: gece yarısı.
  4. Dördünü de düzelt. On koşu yeşil, hiçbir şey tekrar denenmedi.
Hızlı kontrolOrta

Otomatik tekrar deneme açıldı, on koşu da yeşil. Ne olmuştur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Bir test yalnızca başka bir testten sonra çalışınca kırılıyor. Sebep büyük ihtimalle nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Tuzaklar

Kararsız testi silmek ya da kapatmak. Test bir şeyi koruyordu. Önce sebebini bul; gerekiyorsa kısa süreliğine karantinaya al ama bir sahibi ve bir tarihi olsun.

Yerelde hep geçtiği için CI’ı suçlamak. CI makinesi daha yavaş, saat dilimi farklı, testler başka sırada. Bu farklar sebebi gösterir.

Testleri hep aynı sırada çalıştırmak. Paylaşılan durum gizli kalır. Sırayı karıştırınca sorun erken ve tekrarlanabilir şekilde ortaya çıkar.

Kafam karıştı, daha basit anlat

Silme, sebebini bul. CI’daki fark bir ipucudur. Sırayı karıştır, gizli bağımlılık ortaya çıksın.

Hızlı kontrolOrta

HashSet'ten gelen elemanları bir listeyle containsExactly ile karşılaştıran test neden kararsızdır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Derinleş · Faiz ve ekstre testleri: kararsızlığın dört ilacı 4 dosya · ~53 satır · ilk okumada atlayabilirsin
Proje dosyaları

src/main/java/com/bank/interest/ InterestService.java Servis: saat koda dışarıdan veriliyor; testte sabit bir an kullanılabiliyor.

src/main/java/com/bank/interest/InterestService.java
@Service
class InterestService {
private final Clock clock;
private final RateTable rates;
// Spring injects the system clock; a test passes a fixed one.
InterestService(Clock clock, RateTable rates) {
this.clock = clock;
this.rates = rates;
}
BigDecimal dailyInterest(BigDecimal balance) {
LocalDate today = LocalDate.now(clock);
return balance.multiply(rates.dailyRateOn(today)).setScale(2, RoundingMode.HALF_EVEN);
}
}

src/test/java/com/bank/interest/ InterestServiceTest.java Saat testi: gece yarısına bir saniye kala, her koşuda aynı sonuç.

src/test/java/com/bank/interest/InterestServiceTest.java
class InterestServiceTest {
private static final ZoneId ISTANBUL = ZoneId.of("Europe/Istanbul");
@Test
void usesTheRateOfTheDayEvenOneSecondBeforeMidnight() {
Clock lateNight = Clock.fixed(LocalDateTime.of(2026, 10, 3, 23, 59, 59).atZone(ISTANBUL).toInstant(), ISTANBUL);
RateTable rates = day -> day.equals(LocalDate.of(2026, 10, 3)) ? new BigDecimal("0.0001") : BigDecimal.ZERO;
BigDecimal interest = new InterestService(lateNight, rates).dailyInterest(new BigDecimal("10000"));
assertThat(interest).isEqualByComparingTo("1.00");
}
}

src/test/java/com/bank/statement/ StatementJobTest.java Ekstre testi: her teste taze bir kutu, sırasız karşılaştırma ve süre yerine koşulu bekleyen Awaitility.

src/test/java/com/bank/statement/StatementJobTest.java
class StatementJobTest {
private InMemoryOutbox outbox;
private StatementJob job;
@BeforeEach
void freshState() { // no static list shared with other tests
outbox = new InMemoryOutbox();
job = new StatementJob(outbox, Executors.newVirtualThreadPerTaskExecutor());
}
@Test
void sendsOneStatementPerAccount() {
job.runFor(List.of("TR01", "TR02"));
// Wait for the condition, not for a guess like Thread.sleep(100).
await().atMost(Duration.ofSeconds(5))
.untilAsserted(() -> assertThat(outbox.recipients()).containsExactlyInAnyOrder("TR01", "TR02"));
}
}

src/test/resources/ junit-platform.properties JUnit ayarı: test metotları her koşuda karışık sırayla çalışır; paylaşılan durum erken yakalanır.

src/test/resources/junit-platform.properties
# Run test methods in a different order every time: shared state shows up early, not on a Friday.
junit.jupiter.testmethod.order.default=org.junit.jupiter.api.MethodOrderer$Random

Kendini sına

Şimşek turu1/4

Kod değişmediyse kırılan test mutlaka CI'ın hatasıdır.

Soru 1/3İleri

Testleri her koşuda karışık sırada çalıştırmanın faydası nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 1 Kararsız bir testin her zaman bir sebebi vardır. En sık dört sebep: o anki saat, garanti edilmeyen bir sıra, testler arasında paylaşılan durum ve sabit süre beklemek.
  2. 2 Her sebebin kendi ilacı var: saati enjekte et, sırasız karşılaştır, her teste taze durum ver, süre yerine koşulu bekle.
  3. 3 Tekrar deneme kırmızıyı yeşile çevirir ama sebebi bırakır. Gerçek bir hata da aynı şekilde gizlenebilir.
Sonraki kapı Kapsama raporu yüzde yüz diyor. Yine de havale ücretindeki bir sınır hatası canlıya çıktı ve hiçbir test kırmızı olmadı. Nasıl? Kapsama ve Mutasyon — Yüzde Yüz Test, Hata Nasıl Geçti? · 8 dk

4 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı