TDD'ye doğru sonuçların nasıl döndürüldüğü


12

Yeni bir projeye başlıyorum ve tasarımı yönlendirmek için TDD'yi kullanmak için çok uğraşıyorum. Yıllardır zorluyorum ve nihayet düzgün bir şekilde nasıl yapılacağını öğrenirken projeyi kullanmak için fazladan zaman harcamak için onay aldım.

Bu, mevcut bir sisteme bağlamak için yeni bir modüldür. Şu anda, tüm veri erişimi çoğunlukla veritabanı saklı yordamları üzerinde ince bir sargı olan web hizmetleri aracılığıyla gerçekleşir.

Bir gereksinim, belirli bir mağaza için, bu uygulama için geçerli kabul edilen tüm Satın Alma Siparişlerini iade etmemdir. PO'nun, gönderim tarihi mağazaların açılış tarihinden belirli bir aralığa düşmesi durumunda geçerli sayılır (bu yeni mağazalar içindir).

Şimdi, bu mantığı uygulama koduna koyamıyorum, çünkü yukarıdaki kısıtlama göz önüne alındığında, bu mağazaya başvurabilecek düzine almak için bir milyon PO geri getirmeyeceğim.

Tarih aralığını GetValidPOs proc'a geçirebileceğimi ve geçerli PO'ları döndürmek için bu değerleri kullanmasını sağlayabiliyordum. Ancak, geçerli bir PO olarak kabul edilen şeye başka bir gereksinim eklersek ne olur?

Bunu nasıl test edebilirim ve çalışmaya devam ettiğini nasıl doğrulayabilirim? ORM kullanmıyoruz ve gerçekleşmesi pek mümkün değil. Ve testimde DB'yi arayamam.

Sıkıştım.

Diğer düşüncem, geçerli verileri döndüren bazı taklitler, bazı kötü veriler döndüren ve kötü veri oluşursa yerel havuzun bir istisna atmasını ve geçersiz verilerin GetValidPOs proc ( testte kullanılan alay).

Bu mantıklı mı? Yoksa daha iyi bir yol var mı?

GÜNCELLEME: Görünüşe göre EF'i kullanabiliyorum. Şimdi sadece nasıl kullanılacağını anlamaya ve test edilebilir hale getirmeye ihtiyacım var, yine de saklı prosedürlere ve çeşitli veritabanlarına dağılmış olmanın zorluğuna güvenebiliyorum.


Meraktan, neden sadece düz bir SQL ifadesine sahip geçerli PO'ları seçemiyorsunuz? (Bu soru veya cevap bir çözüm anlamına gelmez.)
scarridge

Yanıtlar:


7

Bu, TDD çağındaki saklı prosedürlerin önemli bir dezavantajıdır. Şimdi bile bazı gerçek iniş çıkışları var, ancak tanım gereği, depolanmış bir proc uygulayan herhangi bir test bir birim test değildir; en iyi ihtimalle bir entegrasyon testidir.

Mimarinin bir ORM kullanmak için değişemeyeceği varsayılarak kabul edilen çözüm, bu testleri birim test takımına koymamaktır; bunun yerine testleri bir entegrasyon paketine koyun. Çalıştığını doğrulamak istediğinizde testi yine de çalıştırabilirsiniz, ancak testi kurmanın doğasında olan maliyet (uygun test verileri ile bir DB başlatma) yüksek olduğundan ve derlemenizin birim test aracısının kaynaklara dokunmadığı için erişebilirse, ünite test paketinde olmamalıdır.

Yine de alay edebileceğiniz bir DAO sınıfına birim testi (ADO.NET sınıfları) yapamayacağınız herhangi bir şeyi soyutlayarak, veri gerektiren kodu test edebilirsiniz. Daha sonra, kod tüketerek beklenen aramaların yapıldığını doğrulayabilir ve çeşitli kullanım durumlarının test edilmesine izin veren gerçek dünya davranışını (sonuç bulma gibi) yeniden oluşturabilirsiniz. Ancak, SqlCommand'ın depolanan proc'u çağırmak için fiili kurulumu, komut oluşturma işleminden komut oluşturma işlemini kesip komut yürütücüsünü alay ederek birim test edebileceğiniz en son şeydir. Bu endişelerin ayrılığı gibi görünüyorsa, olabilir; Unutmayın, "çok fazla dolaylı katmana sahip olmak dışında, başka bir dolaylı katman tarafından çözülemeyen bir sorun yoktur". Bir noktada "yeterli; bunu birim olarak test edemiyorum,"

Diğer seçenekler:

  • Depolanan işlemi SQLite gibi "kısa ömürlü" bir DBMS örneği kullanarak test edin. Bir ORM kullanırken bunu yapmak genellikle daha kolaydır, ancak test daha sonra "bellekte" (veya test paketinde bulunan önceden ayarlanmış bir veritabanı dosyasıyla) yapılabilir. Hala bir birim testi değil, ancak yüksek derecede izolasyonla çalıştırılabilir (DBMS, çalışan işlemin bir parçasıdır ve uzaktan bağlandığınız, başka birinin çakışan test paketinin ortasında olabilecek bir şey değildir). Dezavantajı, depolanan proctaki değişikliklerin, değişikliği yansıtan test yapılmadan üretimde gerçekleşebilmesidir, bu nedenle değişikliğin ilk önce bir test ortamında yapıldığından emin olmak için disiplinli olmanız gerekir.

  • Bir ORM'ye yükseltmeyi düşünün. Linq sağlayıcısı olan bir ORM (hemen hemen tüm ortak kullanımda bir tane vardır) sorguyu bir Linq ifadesi olarak tanımlamanıza izin verir; bu ifade daha sonra, uygulanacak test verilerinin bellek içi bir koleksiyonuna sahip olan alaycı bir Havuz'a verilebilir. Böylece DB'ye dokunmadan sorgunun doğru olduğunu doğrulayabilirsiniz (Linq sağlayıcısının sorguyu doğru şekilde sindirebildiğini test etmek için sorguyu bir entegrasyon ortamında çalıştırmanız gerekir).


2
-1 çünkü TDD! = Birim testi. TDD yaparken entegrasyon seviyesi testleri dahil etmek için gayet iyi.
Steven A. Lowe

Birim testi, test odaklı geliştirmenin bir alt kümesidir. Test odaklı bir geliştirmede, sisteminizin yürüyen bir iskeletini oluşturacak ve daha sonra bu sistem üzerinde birim, entegrasyon ve fonksiyonel testler gerçekleştireceksiniz. Entegrasyon, birim veya kabul testleriniz başarısız olur, daha sonra bunları geçip başka testler yazarsınız.
CodeART

1
Hepsini anlıyorum, ikiniz de. Entegrasyon testi olması gerektiğini nerede söyledim, TDD yapamayacağınız anlamına mı geliyordu? Demek istediğim, saklı bir yordamın tek başına test edilememesi, bu da kod tabanınızın olabildiğince fazla olmasını istediğiniz bir şeydi. Bunun yerine SP'leri test etmek daha karmaşık, daha uzun süre çalışan entegrasyon testleri gerektirir; yine de manuel testten daha iyiyken, entegrasyon ağır bir test paketinin çalışması saatler alabilir ve CI çabaları üzerinde zararlı bir etkiye sahip olabilir.
KeithS

SP testi genellikle test veritabanında belirli bir veri seti gerektirir; beklenen sonuçları elde etmek için veritabanını uygun duruma getirmek için kod aslında gerçekte kullandığınız koddan çok daha fazla LoC ve birkaç kat daha uzun çalışıyor. Bu ayrıca test takımının zaman karmaşıklığını bir araya getirir ve genellikle kurulum her bir test için tekrarlanmalıdır (ve muhtemelen her SP için, içinde sorgunun her bir fonksiyonel gereksiniminin karşılandığını test etmek için birkaç tane olmalıdır).
KeithS

Saklı yordamlar ayrı ayrı test edilebilir. Başka nasıl onaylanabilirler? Transact SQL için tSQLt ( tsqlt.org ) var
kevin

4

Benim tavsiyem bölmek ve fethetmek . Şu an için veritabanını ve kalıcılığı unutun ve depolarınızın veya veri erişim nesnelerinizin sahte uygulamalarını test etmeye odaklanın.

Şimdi, bu mantığı uygulama koduna koyamıyorum, çünkü yukarıdaki kısıtlama göz önüne alındığında, bu mağazaya başvurabilecek düzine almak için bir milyon PO geri getirmeyeceğim.

Satın alma emirlerini veren havuzu alay ediyorum. Yirmi tek satınalma siparişiyle bir alay oluşturun.

Tarih aralığını GetValidPOs proc'a geçirebileceğimi ve geçerli PO'ları döndürmek için bu değerleri kullanmasını sağlayabiliyordum. Ancak, geçerli bir PO olarak kabul edilen şeye başka bir gereksinim eklersek ne olur?

GetValidPO'lara veritabanı yordamı yerine alayınızı çağırması için bir çağrı yapın.

Bunu nasıl test edebilirim ve çalışmaya devam ettiğini nasıl doğrulayabilirim? ORM kullanmıyoruz ve gerçekleşmesi pek mümkün değil. Ve testimde DB'yi arayamam.

Bir taklitten doğru verilerin döndürüldüğünden emin olmak için bir birim testine ihtiyacınız vardır.

Veritabanından doğru verilerin döndürüldüğünden emin olmak için bir entegrasyon testine de ihtiyacınız vardır. Entegrasyon testi bazı yapılandırma ve temizleme gerektirir. Örneğin, tümleştirme sınamasını çalıştırmadan önce, bir komut dosyası çalıştırarak veritabanınızı tohumlayın. Komut dosyanızın çalıştığını doğrulayın. Saklı yordamlarınızı çağırarak veritabanını sorgulayın. Sonuçlarınızın doğru olduğundan emin olun. Veritabanını temizleyin.

Diğer düşüncem, geçerli verileri döndüren bazı taklitler, bazı kötü veriler döndüren ve kötü veri oluşursa yerel havuzun bir istisna atmasını ve geçersiz verilerin GetValidPOs proc ( testte kullanılan alay).

Daha önce de söylediğim gibi, sorgulayabileceğiniz en azından bazı verileri döndüren bir alay gerekir.

Verileri sorguladığınızda, sisteminizin istisnaları zarif bir şekilde işleyebildiğinden emin olmak istersiniz. Bu nedenle, belirli senaryolarda istisnalar atmak için davranışı alay edersiniz. Daha sonra sisteminizin bu istisnaları nazikçe ele alabilmesini sağlamak için testler yazarsınız.


Ben de bunu yapmaya çalışıyorum. Veri erişimimiz bir ORM kullanmaya elverişli olmadığından, sahte ile aynı şekilde çalışacak gerçek bir uygulama yazmakta zorluk çekiyorsunuz. İhtiyacım olan verilerin çoğu çeşitli sistemlerde ve web servisleri üzerinden erişilmesi gerekiyordu ... güncelleme sırasında bile.
CaffGeek

0

Birim testi Java veya Javascript'in, Java için Java dilini kullanarak birim testleri yazmak ve Javascript ile birim testi yapmak gibi, saklı yordamları yazmaya yönlendirmek için otomatik testler yazmak, aradığınız birim testi kitaplığının depolandığı anlamına gelir prosedürleri.

Başka bir deyişle, saklı yordamları test etmek için saklı yordamlar kullanın çünkü:

  • prosedür dilinde geliştiğiniz için testlerinizi prosedür dilinde yazabilme yeteneğine sahip olmalısınız
  • Prosedür dilinizde testler yapmak, prosedür dilinde yeteneklerinizi artıracak ve bu da ürün geliştirmenize yardımcı olacaktır
  • DB'nizin sağladığı tüm araçlara doğrudan erişebileceksiniz ve bu araçları da kullanabilirsiniz, ünite testlerinizi mümkün olduğunca basit tutun
  • test ettikleri prosedürlerle aynı DB'de saklanan birim testleri hızlı olacaktır (hızlar gibi birim testine en yakın şey), çünkü sistem sınırlarını geçmiyorsunuz

Tıpkı bir OO dilindeki TDD gibi, birim testinizin prosedür için neye ihtiyaç duyduğunu test etmek için sadece bir satır veri kurmasını istersiniz (minimalizm, sadece basit testlerinize ihtiyaç duyduğunuz şey). Bunun sonucu, saklanan her prosedür için birkaç basit birim testine sahip olmanızdır. Bu basit testlerin bakımı, testin gerçekten ihtiyaç duyduğu şeyle kolayca eşleşmeyen büyük bir veri kümesine bağlı karmaşık testlere sahip olmaktan daha kolay olacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.