Otomasyon QAKıdemli Otomasyon QA Mühendisi

Etkinlik kaynaklı alan agregatları için etkinlik akışı sıralama güvence gereksinimlerini zorlayan, yasadışı durum geçişlerini invariant kontrolü ile tespit eden ve simüle edilmiş kalıcılık hatalarında anlık durum kurtarma bütünlüğünü doğrulayan bir otomatik doğrulama çerçevesi nasıl inşa edersiniz?

Hintsage yapay zeka asistanı ile mülakatları geçin

Sorunun cevabı

Sorunun tarihi

Etkinlik kaynaklama, tam denetim izleri ve zamansal sorgulama yetenekleri gerektiren alanlar için kritik bir desen olarak ortaya çıktı. Geleneksel CRUD mimarilerinin aksine, durum geçişlerini eklemeli bir depoda değişmez etkinlikler olarak saklar ve olay yeniden oynatması yoluyla agregat durumunu yeniden inşa eder. 2010'larda finansal ve sağlık sistemlerinde benimsenmenin artmasıyla QA ekipleri, geleneksel sahteleme stratejilerinin aggregate’lar ve etkinlik depoları arasındaki entegrasyon sorunlarını yakalamakta başarısız olduğunu keşfetti. Özellikle iyimser eşzamanlılık kontrolü ve anlık durum optimizasyon mekanizmaları ile ilgili olarak.

Problem

Geleneksel birim testleri, agregatları sahte depo kullanarak izole eder, bu da etkinlik deposunun tutarlılık garantilerini tamamen göz ardı eder. Bu, kritik hata modlarını gözden kaçırır: akran etkinlik eklemeleri olay akışı sürüm çakışmalarına yol açabilir, bozulmuş anlık durumlar (agregat durumunu önbelleğe alarak performans optimizasyonları) eski veriler döndürebilir ve yasadışı durum geçişleri yalnızca belirli etkinlik dizileri sırasında gerçekleşir. Otomatik doğrulama olmadan, bu hatalar yalnızca üretimde yarış koşulları altında ortaya çıkar ve geriye dönük olarak uzlaşılması neredeyse imkansız olan veri tutarsızlığına yol açar.

Çözüm

TestContainers kullanarak gerçek EventStoreDB veya Apache Kafka örneklerini çalıştıran bir entegrasyon test çerçevesi uygulayın. Karmaşık senaryolar oluşturmak için değişmez etkinlik oluşturucular ile Given-When-Then desenini benimseyin. Rastgele etkinlik dizileri ve iç içe geçmeleri otomatik olarak doğrulamak için Property-Based Testing ( jqwik veya ScalaCheck aracılığıyla) uygulayın, böylece agregat invariantlarının tarihine bakılmaksızın geçerli olmasını sağlayın. Ağ hatalarını ve disk gecikmesini Toxiproxy kullanarak enjekte edin ve çöküntüler sonrası anlık durum kurtarmayı doğrulayın. Anlık durumlardan yeniden inşa edilen agregatların tam etkinlik yeniden oynatmasıyla byte-for-byte eşleştiğini doğrulayın.

@Test public void shouldMaintainInvariantAfterConcurrentEventAppends() { // Verilen: Versiyon 10'da anlık duruma sahip agregat String streamId = "order-" + UUID.randomUUID(); OrderAggregate aggregate = new OrderAggregate(streamId); aggregate.loadFromSnapshot(snapshotAtVersion10); // Ne zaman: Ödeme İşlendi'nin eşzamanlı eklemesini simüle etme List<DomainEvent> concurrentEvents = Arrays.asList( new ItemAdded("SKU-123", 2), // v11 new PaymentProcessed(BigDecimal.valueOf(100.00)) // v12 ); // O zaman: İnvaryantı doğrulayın (sepetinizde olmayan ürünler için ödeme yapılamaz) assertThrows(IllegalStateException.class, () -> { aggregate.apply(concurrentEvents); }); // Anlık durum kurtarmanın tam yeniden oynatma ile eşit olduğunu doğrulayın OrderAggregate fromSnapshot = repository.loadFromSnapshot(streamId); OrderAggregate fromReplay = repository.loadFromEvents(streamId); assertEquals(fromSnapshot.calculateHash(), fromReplay.calculateHash()); }

Hayattan bir durum

Günde 50.000 siparişi işleyen bir işletmenin e-ticaret platformu, sipariş yönetim sınırlı bağlamı için etkinlik kaynaklamayı benimsedi. Her OrderAggregate, OrderCreated, ItemAdded ve PaymentProcessed gibi etkinlikler yaymaktaydı. Yüksek trafiği yönetmek için sistem, tüm tarihleri yeniden oynatmayı önlemek için her 20 etkinlikte bir anlık durum oluşturuyordu.

Kara Cuma sırasında sistem, ödemelerin alındığı ancak stok seviyelerinin değişmediği "hayalet envanter" hataları ile karşı karşıya kaldı. Kök neden analizi, yüksek eşzamanlılık altında anlık durum kalıcılığının etkinlik eklemeleriyle birkaç milisaniye geride kaldığını ortaya çıkardı. Bu eski anlık durumlardan agregatları yeniden inşa ederken, son ItemAdded etkinlikleri, kendisi hatalı olan idempotency işleme mantığı tarafından iki kez işlendi ve bu da stok hesaplamalarında hatalara neden oldu.

Çözüm A: Anlık Durum Olmadan Saf Etkinlik Yeniden Oynatma

Test mimarisinden anlık durumu tamamen çıkarın, her testin ilk etkinlikten itibaren tam etkinlik akışlarını yeniden oynamasını zorlayın. Artıları: Anlık durum bozulma risklerini tamamen ortadan kaldırır; anlık durum karşılaştırma mantığını kaldırarak test doğrulamalarını basitleştirir; agregatlar her zaman mutlak hakikatten hesaplandığı için matematiksel tutarlılığı garanti eder. Eksileri: Agregatlar olgunlaştıkça test yürütme süresi üssel olarak artar (1000+ etkinlik), CI pipe'larının uygulanabilirliğini azaltır; yalnızca anlık durum oluşturma sırasında ortaya çıkan üretimle ilgili yarış koşullarını tespit etmez; yük altında kullanıcı deneyimini etkileyen performans darboğazlarını maskelemektedir.

Çözüm B: Manuel İkili Karşılaştırma

QA mühendisleri, test yürütmesinden sonra anlık durum dosyalarını manuel olarak dışa aktarır ve işlemlerden önce ve sonra ikili serileştirme karşılaştırması yapmak için farklı araçlar kullanır. Artıları: Serileştirme format değişikliklerinde doğrudan görünürlük sağlar; anlık durum sürümleri ve mevcut agregat kodu arasındaki şema uyumsuzluklarını yakalar; ek altyapı yatırımı gerektirmez. Eksileri: Anlık durum yazımları ve etkinlik eklemeleri arasındaki yarış koşullarını otomatik olarak tespit edemez; doğrulamada insan hatası kaçınılmazdır; zaman damgası hassasiyeti veya JSON anahtar sıralaması gibi küçük biçim değişikliklerine karşı son derece kırılgandır; CI/CD ortamlarında ölçeklenmesi imkansızdır.

Çözüm C: Property-Based Durum Makinesi Doğrulaması

Rastgele geçerli etkinlik dizilerini oluşturmak için jqwik kullanarak Property-Based Testing uygulayın, rastgele aralıklarla anlık durum oluşturmayı zorlayın, Byteman aracılığıyla işlem öldürmelerini enjekte edin ve agregat invariantslarının (örneğin "ödenen miktarın ürün fiyatlarının toplamına eşit olması") yeniden inşa yönteminden bağımsız olarak geçerli olduğunu doğrulayın. Artıları: Anlık durumun, örneğin hızlı arka arkaya ItemAdded etkinlikleri arasında alındığı gibi manuel olarak betimlenemeyen kenar durumlarını otomatik olarak keşfeder; eşzamanlı erişim kalıplarını ve iyimser eşzamanlılık hatalarını doğrular; matematiksel property doğrulaması yoluyla belirleyici hataları tespit eder. Eksileri: Fonksiyonel programlama kavramları ve property tabs test çerçevelerinde önemli uzmanlık gerektirir; doğru tohumlama olmadan, hatalar belirleyici olmayabilir ve yerel olarak yeniden üretmek zor olabilir; binlerce oluşturulan test durumu nedeniyle CI yürütme süresini 15-20 dakika artırır.

Seçilen çözüm ve gerekçe

Ekip, deterministik tohumlama ile Çözüm C'yi seçti (tekrar üretilebilirlik için Git'te saklandı). Bu seçim, Çözüm A'nın anlık durum mekanizmasını tamamen çıkararak gerçekten üretim hatasını gizlemesi, Çözüm B'nin ise anlık durum kalıcılığı ile etkinlik ekleme işlemleri arasında 50 milisaniyelik yarış penceresini yakalayamaması nedeniyle zorunluydu. Property-based testing, anlık durumların iki hızlı ItemAdded etkinliği arasında alındığında, iyimser eşzamanlılık versiyon kontrolünün anlık durum sürümünü olay akışı sürümü ile karşılaştırmak yerine agregat sürümü ile yanlış bir şekilde karşılaştırdığını ortaya koydu; bu, yalnızca belirli iç içe geçmeler altında görünür olan ince bir mantık hatasıdır.

Sonuç

Çerçeve, sürüm eşitsizliği nedeniyle üç kritik hatayı serbest bırakmadan önce tespit etti: eşzamanlı yazmalardaki anlık durum sürüm uyuşmazlığı, PaymentProcessed işleyicisindeki eksik idempotency kontrolleri ve etkinliklerin kiralık akışlar arasında sızmasına neden olan agregat sınır ihlalleri. CI artık her bir derleme başına 5.000 rastgele oluşturulmuş etkinlik sırası yürütüyor. Sipariş durum tutarsızlığı ile ilgili dağıtım sonrası üretim olayları %94 oranında düştü ve anlık durum bozulmasının tespit süre ortalaması 4 saatten 30 saniyeye düştü, otomatik uyarılar yoluyla.

Adayların sıklıkla gözden kaçırdığı noktalar

Zamansal sorguları (zaman yolculuğu) etkinlik kaynaklı sistemlerde nasıl test edersiniz, sistem saati zamanı ile testleri ilişkilendirmeden veya Thread.sleep() kullanmadan?

Adaylar genellikle Thread.sleep() veya sistem saatini manipüle ederek, CI ortamlarında aralıklı olarak başarısız olan geçersiz testler oluşturmaya başvuruyor. Doğru yaklaşım, bir Saat soyutlamasının bağımlılık enjekte edilmesiyle olmaktadır (örneğin Java'da java.time.Clock veya .NET'te Microsoft.Extensions.Internal.ISystemClock gibi).

Testlerde, deterministik bir şekilde ilerleyebilen bir MutableClock veya FixedClock uygulaması enjekte edin. "Dün saat 15:00'te sipariş durumu neydi?" şeklindeki testlerde, saati o an dondurun, komutları yürütün ve bilinen tarihsel duruma karşı doğrulayın. "Siparişler 24 saat sonra otomatik iptale geçiyor" gibi zaman aşımı mantığını test etmek için, yalnızca enjekte edilen saati 25 saat ilerletin ve beklenen OrderExpired etkinliğinin çıktığını doğrulayın. Bu, testlerin milisaniyeler içinde yürütülmesini sağlarken karmaşık zamansal iş kurallarıyla doğru bir şekilde doğrulama yapar.

Bir etkinlik deposundan test verilerini fiziksel olarak silmenin neden bir anti-model olarak kabul edildiği ve append-only mantığını ihlal etmeden temiz test ortamlarını nasıl sağladığına dair strateji ne olmalıdır?

Birçok aday, etkinlik akışlarını kısaltmayı veya temizleme bloklarında agregatları silmeyi önerir, bu da etkinlik depolarının mimari kaynağı gereği append-only olduğu anlayışını temelden yanlış anladıklarını gösterir. Fiziksel silme, denetim gereksinimlerini ihlal eder ve genellikle teknik olarak desteklenmez (örneğin EventStoreDB yalnızca mezar silme destekler, gerçek silme değil). Ayrıca, eşzamanlı test çalışmaları, akış adları yeniden kullanıldığında iyimser eşzamanlılık çelişkileri yaşayabilir.

Doğru strateji, UUID'ler (örneğin order-{testRunId}-{uuid}) kullanan eşsiz akış adlandırma kuralları ve filtreleme için kategori tabanlı projeksiyonlar uygulamakla ilgilidir. Entegre testler için, her test sınıfı için izole etkinlik deposu örneklerini çalıştırmak için TestContainers kullanın. Birim testler için, Marten'in hafif belge depolama modunu veya Axon Framework'ün SimpleEventStore'unu kullanarak bellek içi uygulamaları tercih edin. Testler arasında agregat kimliklerini asla yeniden kullanmayın; bunun yerine etkinlik deposunu değişmez bir altyapı olarak ele alın ve sorguları belirli zamansal dilimler veya akış öneklerine sınırlayarak diğer test yürütmelerinden gelen verileri etkili bir şekilde göz ardı edin.

Etkinlik şeması göçlerini (yükseltme) yeni zorunlu alanların mevcut etkinlik türlerine eklenirken geriye dönük uyumluluğun sağlanıp sağlanmadığını nasıl doğrularsınız?

Adaylar genellikle etkinlik kaynaklama gerektirir etkinlik sürümleme ve yükseltme (tarihsel etkinlikleri mevcut şema sürümlerine dönüştürme). OrderCreated V2'ye zorunlu bir alan eklerken, depoda zaten var olan binlerce V1 etkinliği bulunmaktadır ve bunların doğru bir şekilde deserialize edilmesi gerekmektedir.

Test stratejisi, üretimden gelen gerçek serileştirilmiş tarihsel etkinlik JSON'larının altın ustası deposunu korumayı gerektirir. CI'de, bu tarihsel yükleri yükseltme zinciri aracılığıyla deserialize edin ve geçerli V2 nesnelerine mantıklara uygun varsayılanlarla dönüşmesini doğrulayın (örneğin, currencyCode'yu boş bırakmamak için bağlamsal yapılandırmadan türetin). İstenmeyen serileştirme format değişikliklerini algılamak için Onay Testleri uygulayın. Ayrıca, dairesel serileştirmeyi test edin: bir V2 nesnesini alın, onu V1'e (varsa) aşağı çevirin ve ardından V2'ye geri doğru çevirerek eşitliği doğrulayın. Bu, yeni kodun beş yıllık etkinlikleri veri kaybı olmadan işleyebilmesini sağlamak için kritik öneme sahiptir çünkü etkinlikler değişmez denetim izini temsil eder ve üretim veritabanlarında geriye dönük olarak "yamanamazlar."