Aracılığıyla paylaş


Test stratejisi seçme

Genel Bakış'ta açıklandığı gibi, vermeniz gereken temel bir karar, testlerinizin üretim veritabanı sisteminizi (uygulamanızın yaptığı gibi) mı yoksa testlerinizin üretim veritabanı sisteminizin yerini alan bir test çiftine karşı mı çalıştırılacağıdır.

Gerçek bir dış kaynağa karşı test etme ( test çiftiyle değiştirmek yerine) aşağıdaki zorlukları içerebilir:

  1. Çoğu durumda, gerçek dış kaynağa karşı test etmek mümkün veya pratik değildir. Örneğin, uygulamanız kolayca test edilemeyen bazı hizmetlerle etkileşime geçebilir (hız sınırlaması veya test ortamının olmaması nedeniyle).
  2. Gerçek dış kaynağı dahil etmek mümkün olsa bile, bu durum çok yavaş olabilir: bir bulut hizmetinde büyük miktarda test çalıştırmak, testlerin çok uzun sürmesine neden olabilir. Test, geliştiricinin günlük iş akışının bir parçası olmalıdır, bu nedenle testlerin hızla çalıştırılması önemlidir.
  3. Bir dış kaynağa yönelik testlerin yürütülmesi, testlerin birbiriyle etkileşime geçtiği yalıtım sorunları içerebilir. Örneğin, bir veritabanına karşı paralel olarak çalışan birden çok test verileri değiştirebilir ve birbirlerinin çeşitli yollarla başarısız olmasına neden olabilir. Bir test çifti kullanmak, her test kendi bellek içi kaynağına karşı çalıştığından ve bu nedenle diğer testlerden doğal olarak yalıtıldığından bunu önler.

Ancak, bir test double'a karşı geçen testler, programınızın gerçek dış kaynakta çalışırken çalışmasını garanti etmez. Örneğin, bir veritabanı testi çifti büyük/küçük harfe duyarlı dize karşılaştırmaları gerçekleştirebilirken, üretim veritabanı sistemi büyük/küçük harfe duyarlı olmayan karşılaştırmalar yapar. Bu tür sorunlar yalnızca testler gerçek üretim veritabanınızda yürütülürse ortaya çıkar ve bu da bu testleri herhangi bir test stratejisinin önemli bir parçası haline getirir.

Veritabanına karşı sınamak göründüğünden daha kolay olabilir

Gerçek bir veritabanına karşı test etme konusunda yukarıdaki zorluklar nedeniyle geliştiricilere sık sık önce test çiftlerini kullanmaları ve makinelerinde sık sık çalıştırabilecekleri sağlam bir test paketine sahip olmaları istenir; buna karşılık, veritabanını içeren testlerin çok daha az sıklıkta yürütülmesi gerekir ve çoğu durumda çok daha az kapsam sağlar. İkincisine daha fazla düşünmenizi ve veritabanlarının yukarıdaki sorunlardan insanların düşünme eğiliminden çok daha az etkilenebileceğini öneririz:

  1. Günümüzde çoğu veritabanı geliştiricinin makinesine kolayca yüklenebilir. Docker gibi kapsayıcı tabanlı teknolojiler bunu çok kolaylaştırabilir ve Github Workspaces ve Dev Container gibi teknolojiler geliştirme ortamınızın tamamını sizin için (veritabanı dahil) ayarlar. SQL Server kullanırken, Windows'ta LocalDB'ye karşı test etmek veya Linux'ta kolayca bir Docker görüntüsü ayarlamak da mümkündür.
  2. Makul bir test veri kümesiyle yerel bir veritabanında test etme genellikle son derece hızlıdır: iletişim tamamen yereldir ve test verileri genellikle veritabanı tarafında bellekte arabelleğe alınır. EF Core yalnızca SQL Server'a karşı 30.000'den fazla test içerir; bunlar birkaç dakika içinde güvenilir bir şekilde tamamlanıyor, her işlemede CI'de yürütülür ve geliştiriciler tarafından yerel olarak çok sık yürütülür. Bazı geliştiriciler, bunun hız için gerekli olduğu inancıyla bellek içi bir veritabanına ("sahte") başvurur - bu neredeyse hiç böyle bir durum değildir.
  3. Testler verileri değiştirebileceği ve birbiriyle karışabileceği için, gerçek bir veritabanında test çalıştırılırken yalıtım gerçekten bir engeldir. Ancak, veritabanı test senaryolarında yalıtım sağlamak için çeşitli teknikler vardır; üretim veritabanı sisteminize karşı test etme bölümünde bunlara odaklanıyoruz).

Yukarıdakiler, test çiftlerini ayrıştırmak veya bunların kullanılmasına karşı tartışmak için tasarlanmamıştır. Test çiftleri, veritabanı hatası benzetimi gibi aksi halde test edilemeyen bazı senaryolar için gereklidir. Ancak, deneyimlerimize göre kullanıcılar genellikle yukarıdaki nedenlerle veritabanlarına karşı testten çekinir ve bunun yavaş, zor veya güvenilir olmadığına inanır. Üretim veritabanı sisteminize karşı test etmek, veritabanınıza hızlı ve yalıtılmış testler yazmak için yönergeler ve örnekler sağlayarak bu sorunu gidermeyi amaçlar.

Farklı test çift türleri

Test çiftleri , çok farklı yaklaşımları kapsayan geniş bir terimdir. Bu bölüm, EF Core uygulamalarını test etmek için test çiftlerini içeren bazı yaygın teknikleri kapsar:

  1. SQLite'i (bellek içi mod) üretim veritabanı sisteminizi değiştirerek sahte veritabanı olarak kullanın.
  2. Ef Core bellek içi sağlayıcısını, üretim veritabanı sisteminizi değiştirerek sahte bir veritabanı olarak kullanın.
  3. Sahte veya saplama DbContext ve DbSet.
  4. EF Core ile uygulama kodunuz arasında bir depo katmanı tanıtın ve bu katmanı taklit edin veya saplayın.

Aşağıda her yöntemin ne anlama geldiğini keşfedecek ve diğer yöntemlerle karşılaştıracağız. Her birini tam olarak anlamak için farklı yöntemleri okumanızı öneririz. Üretim veritabanı sisteminizi içermeyen testler yazmaya karar verdiyseniz, veri katmanının kapsamlı ve güvenilir saplaması/sahtesini sağlayan tek yaklaşım depo katmanıdır. Ancak bu yaklaşımın uygulama ve bakım açısından önemli bir maliyeti vardır.

Bir veritabanı sahte olarak SQLite

Olası bir test yaklaşımı, üretim veritabanınızı (e.g. SQL Server) SQLite ile değiştirmek ve bunu etkili bir şekilde "sahte" test olarak kullanmaktır. Kurulum kolaylığının yanı sıra, SQLite'in özellikle test için yararlı olan bir bellek içi veritabanı özelliği vardır: her test kendi bellek içi veritabanında doğal olarak yalıtılır ve gerçek dosyaların yönetilmesi gerekmez.

Ancak bunu yapmadan önce EF Core'da farklı veritabanı sağlayıcılarının farklı davrandığını anlamak önemlidir. EF Core, temel alınan veritabanı sisteminin her yönünü soyutlamayı denemez. Temel olarak bu, SQLite'e karşı test etme işleminin SQL Server'da veya diğer veritabanlarında olduğu gibi aynı sonuçları garanti etmediği anlamına gelir. Olası davranış farklılıklarına bazı örnekler aşağıda verilmiştir:

  • Aynı LINQ sorgusu farklı sağlayıcılarda farklı sonuçlar döndürebilir. Örneğin, SQL Server varsayılan olarak büyük/küçük harfe duyarlı olmayan dize karşılaştırması yaparken, SQLite büyük/küçük harfe duyarlıdır. Bu, testlerinizin SQL Server'da başarısız olacakları SQLite'e (veya tam tersi) karşı geçmesine neden olabilir.
  • SQL Server üzerinde çalışan bazı sorgular SQLite'te desteklenmez çünkü bu iki veritabanındaki tam SQL desteği farklıdır.
  • Sorgunuz SQL Server EF.Functions.DateDiffDaygibi sağlayıcıya özgü bir yöntem kullanıyorsa bu sorgu SQLite'te başarısız olur ve test edilemez.
  • Ham SQL çalışabilir veya tam olarak ne yapıldığına bağlı olarak başarısız olabilir veya farklı sonuçlar döndürebilir. SQL diyalektleri veritabanları arasında birçok yönden farklıdır.

Testleri üretim veritabanı sisteminizde çalıştırmaya kıyasla, SQLite'i kullanmaya başlamak nispeten kolaydır ve birçok kullanıcı bunu yapar. Ne yazık ki, ef core uygulamalarının başında gibi görünmeseler bile, yukarıdaki sınırlamalar zamanla sorunlu hale gelir. Sonuç olarak, testlerinizi gerçek veritabanınıza yazmanızı veya test çiftini kullanmak mutlak bir gereklilikse, aşağıda açıklandığı gibi bir depo düzeninin maliyetini eklemenizi öneririz.

Test için SQLite kullanma hakkında bilgi için bu bölüme bakın.

Sahte veritabanı olarak bellek içi

EF Core, SQLite'e alternatif olarak bellek içi bir sağlayıcıyla birlikte gelir. Bu sağlayıcı başlangıçta EF Core'un dahili testini desteklemek için tasarlanmış olsa da, bazı geliştiriciler EF Core uygulamalarını test ederken bunu sahte veritabanı olarak kullanır. Bunu yapmak kesinlikle önerilmez: Sahte bir veritabanı olarak bellek içi SQLite ile aynı sorunlara sahiptir (yukarıya bakın), ancak ek olarak aşağıdaki ek sınırlamalar vardır:

  • Bellek içi sağlayıcı genellikle ilişkisel bir veritabanı olmadığından SQLite sağlayıcısından daha az sorgu türünü destekler. Üretim veritabanınıza kıyasla daha fazla sorgu başarısız olur veya farklı davranır.
  • İşlemler desteklenmez.
  • Ham SQL tamamen desteklenmiyor. Sql, SQLite ve üretim veritabanınızda aynı şekilde çalıştığı sürece ham SQL kullanmanın mümkün olduğu SQLite ile karşılaştırın.
  • Bellek içi sağlayıcı performans için iyileştirilmemiştir ve genellikle bellek içi modda (hatta üretim veritabanı sisteminizde) SQLite'ten daha yavaş çalışır.

Özetle, bellek içi SQLite'in tüm dezavantajlarına ve birkaç tanesine daha sahiptir ve karşılığında hiçbir avantaj sunmamıştır. Basit, bellek içi sahte bir veritabanı arıyorsanız bellek içi sağlayıcı yerine SQLite kullanın; ancak aşağıda açıklandığı gibi bunun yerine depo düzenini kullanmayı göz önünde bulundurun.

Test için bellek içi kullanımı hakkında bilgi için bu bölüme bakın.

DbContext ve DbSet'i taklit etme veya saplama

Bu yaklaşım genellikle ve test çifti DbContext DbSetoluşturmak için bir sahte çerçeve kullanır ve bu çiftlere karşı test eder. Sahte uygulamaDbContext, veya SaveChanges()çağrıları Add gibi çeşitli sorgu dışı işlevleri test etmek için iyi bir yaklaşım olabilir ve kodunuzun bunları yazma senaryolarında çağırdığını doğrulamanıza olanak sağlar.

Ancak sorgular üzerinde IQueryablestatik uzantı yöntemi çağrıları olan LINQ işleçleri aracılığıyla ifade edildiği için sorgu işlevselliğini düzgün bir şekilde taklit DbSet etmek mümkün değildir. Sonuç olarak, bazı kişiler "sahte " DbSethakkında konuştuklarında, asıl anlamları bir bellek içi koleksiyon tarafından yedeklenen bir DbSet oluşturmaları ve ardından sorgu işleçlerini basit IEnumerablebir koleksiyon gibi bellekte bu koleksiyona karşı değerlendirmeleridir. Sahte yerine, bu aslında bir tür sahtedir, burada bellek içi koleksiyon gerçek veritabanının yerini alır.

Yalnızca DbSet kendisi sahte olduğundan ve sorgu bellek içinde değerlendirildiğinden, bu yaklaşım EF Core bellek içi sağlayıcısını kullanmaya çok benzer olur: her iki teknik de bir bellek içi koleksiyon üzerinden .NET'te sorgu işleçlerini yürütür. Sonuç olarak, bu teknik aynı dezavantajlardan da muzdariptir: sorgular farklı davranır (örn. büyük/küçük harf duyarlılığı konusunda) veya yalnızca başarısız olur (örn. sağlayıcıya özgü yöntemler nedeniyle), ham SQL çalışmaz ve işlemler en iyi şekilde yoksayılır. Sonuç olarak, bu teknik genellikle herhangi bir sorgu kodunu test etme amacıyla önlenmelidir.

Depo düzeni

Yukarıdaki yaklaşımlar EF Core'un üretim veritabanı sağlayıcısını sahte bir test sağlayıcısıyla değiştirmeye veya bellek içi koleksiyon tarafından yedeklenen bir DbSet oluşturma girişiminde bulundu. Bu teknikler, programın LINQ sorgularını (SQLite veya bellekte) değerlendirmeye devam etmeleri açısından benzerdir ve sonuçta yukarıda özetlenen zorlukların kaynağı budur: belirli bir üretim veritabanında yürütülecek şekilde tasarlanmış bir sorgu sorunsuz bir şekilde başka bir yerde güvenilir bir şekilde yürütülemez.

Düzgün ve güvenilir bir test çifti için, uygulama kodunuzla EF Core arasında aracılık yapan bir depo katmanı eklemeyi göz önünde bulundurun. Deponun üretim uygulaması gerçek LINQ sorgularını içerir ve bunları EF Core aracılığıyla yürütür. Testte depo soyutlaması, gerçek LINQ sorgularına gerek kalmadan doğrudan saplanır veya sahte hale getirilerek EF Core'un test yığınınızdan tamamen kaldırılmasına ve testlerin yalnızca uygulama koduna odaklanmasına olanak sağlar.

Aşağıdaki diyagram, veritabanı sahte yaklaşımını (SQLite/bellek içi) depo düzeniyle karşılaştırır:

Sahte sağlayıcının depo düzeniyle karşılaştırılması

LINQ sorguları artık test kapsamında olmadığından, doğrudan uygulamanıza sorgu sonuçları sağlayabilirsiniz. Başka bir deyişle, önceki yaklaşımlar kabaca sorgu girişlerini saptamaya (örneğin, SQL Server tablolarını bellek içi olanlarla değiştirme) izin verir, ancak ardından gerçek sorgu işleçlerini bellek içinde yürütmeye devam eder. Buna karşılık depo düzeni, sorgu çıkışlarını doğrudan saptamanıza olanak tanıyarak çok daha güçlü ve odaklanmış birim testi yapmanızı sağlar. Bunun işe yarayacağı için deponuzun IQueryable-dönüş yöntemlerini kullanıma sunmadığını unutmayın çünkü bunlar bir kez daha saplanamaz; Bunun yerine IEnumerable döndürülmelidir.

Ancak, depo deseni IEnumerable-dönüş yönteminde her (test edilebilir) LINQ sorgusunu kapsüllemesini gerektirdiğinden, uygulamanıza ek bir mimari katman uygular ve uygulamak ve bakımını yapmak için önemli maliyetler doğurabilir. Özellikle gerçek veritabanına yönelik testlerin depo tarafından kullanıma sunulan sorgular için hala gerekli olma olasılığı göz önünde bulundurulduğunda, bir uygulamanın nasıl test edilmesi gerektiği konusunda seçim yapılırken bu maliyet indirime alınmamalıdır.

Depoların yalnızca test dışında avantajları olduğunu belirtmek gerekir. Tüm veri erişim kodunun uygulamaya yayılmak yerine tek bir yerde toplanmasını sağlarlar ve uygulamanızın birden fazla veritabanını desteklemesi gerekiyorsa, depo soyutlaması sağlayıcılar arasında sorguların ince ayarı için çok yararlı olabilir.

Depoyla testi gösteren bir örnek için bu bölüme bakın.

Genel karşılaştırma

Aşağıdaki tablo, farklı test tekniklerinin hızlı ve karşılaştırmalı bir görünümünü sağlar ve hangi işlevselliğin hangi yaklaşım altında test edilebileceğini gösterir:

Özellik Bellek içi Bellek içi SQLite Mock DbContext Depo düzeni Veritabanında test etme
Test çift türü Sahte Sahte Sahte Sahte/saplama Gerçek, çift değil
Ham SQL mi? Hayır -Sına bağ -lıdır Hayır Evet Yes
Hareket? Hayır (yoksayıldı) Yes Evet Evet Yes
Sağlayıcıya özgü çeviriler mi? Hayır Hayır Hayır Evet Yes
Tam sorgu davranışı? -Sına bağ -lıdır -Sına bağ -lıdır -Sına bağ -lıdır Yes Yes
LINQ'i uygulamanın herhangi bir yerinde kullanabilir misiniz? Yes Evet Yes Hayır* Yes

* Tüm test edilebilir veritabanı LINQ sorguları, saplanması/kopyalanması için IEnumerable-dönüşlü depo yöntemlerinde kapsüllenmelidir.

Özet

  • Geliştiricilerin, gerçek üretim veritabanı sistemleriyle çalışan uygulamalarının iyi bir test kapsamına sahip olması önerilir. Bu, uygulamanın gerçekten üretimde çalıştığından ve uygun tasarımla testlerin güvenilir ve hızlı bir şekilde yürütülebileceğine dair güven sağlar. Bu testler her durumda gerekli olduğundan, oradan başlamak iyi bir fikirdir ve gerekirse test çiftlerini kullanarak test eklemek iyi bir fikirdir.
  • Test çiftini kullanmaya karar verdiyseniz, sahte bir EF Core sağlayıcısı (Sqlite/bellek içi) kullanmak veya sahtesini kullanmak yerine EF Core'un üzerinde veri erişim katmanınızı saptamanıza veya sahtesini yapmanıza olanak tanıyan depo desenini DbSetuygulamanızı öneririz.
  • Depo düzeni bir nedenle uygun bir seçenek değilse SQLite bellek içi veritabanlarını kullanmayı göz önünde bulundurun.
  • Test amacıyla bellek içi sağlayıcıdan kaçının; bu önerilmez ve yalnızca eski uygulamalar için desteklenir.
  • Sorgulama amacıyla sahte DbSet işlem yapmaktan kaçının.