Birim Testleri ve veritabanları: Hangi noktada gerçekten veritabanına bağlanırım?


37

Bir veritabanına bağlanan test sınıflarının, örneğin "Test sınıfları hizmet vermeli mi ..." ve "Birim testi - Veritabanı ile birleştirilmiş uygulama" gibi soruların yanıtları vardır .

Kısacası, bir veritabanına bağlanması gereken bir A sınıfı olduğunu varsayalım. A'nın gerçekten bağlanmasına izin vermek yerine, A'ya bağlanmak için kullanabileceği bir arabirim sağlar. Test için bu arayüzü bazı şeylerle uygularsınız - elbette bağlantı kurmadan. B sınıfı A'yı başlatırsa, A'ya "gerçek" bir veritabanı bağlantısını geçmesi gerekir, ancak B, bir veritabanı bağlantısı açar. Bu, B testini yapmak anlamına gelir; B'ye bağlantıyı enjekte edersiniz.

Öyleyse hangi noktada "burada bir veritabanından veri alıyorum ve bu kod için bir birim testi yazmayacağım" demeliyim?

Başka bir deyişle: Bazı sınıfta kodunda bir yerde olmalıdır diyoruz sqlDB.connect()veya buna benzer. Bu sınıfı nasıl test ederim?

Ve bir GUI veya dosya sistemi ile ilgilenmesi gereken kodla aynı mı?


Birim testi yapmak istiyorum. Başka türlü bir test sorumla ilgili değil. Sadece bir sınıfı test edeceğimi biliyorum (Ben de sana katılıyorum Kilian). Şimdi, bazı sınıfların bir DB'ye bağlanması gerekiyor. Eğer bu sınıfı test etmek ve "Bunu nasıl yaparım?" Diye sormak istersem, birçok kişi şöyle der: "Bağımlılık Enjeksiyonunu Kullan!" Fakat bu sadece sorunu başka bir sınıfa kaydırır, değil mi? Öyleyse soruyorum, gerçekten, gerçekten bağlantıyı kuran sınıfı nasıl test ederim?

Bonus sorusu: Buradaki bazı cevaplar "Sahte nesneler kullanın!" Bu ne anlama geliyor? Test edilen sınıfın dayandığı sınıflarla alay ediyorum. Şimdi test edilen sınava şimdi alayım mı ve alayı sınamayayım mı (hangisi Şablon Yöntemleri kullanma fikrine yakın, aşağıya bakınız)?


Test ettiğiniz veritabanı bağlantısı mı? Bellek veritabanında geçici bir derleme ( derby gibi ) oluşturmak kabul edilebilir mi?

@MichaelT Yine de bellekteki geçici DB veri tabanını gerçek bir veritabanıyla değiştirmek zorundayım. Nerede? Ne zaman? Ünite nasıl test edilir? Yoksa bu kodu test etmemek uygun mudur?
TobiMcNamobi

3
Veri tabanı hakkında "birim test" için hiçbir şey yoktur. Diğer insanlar tarafından korunur ve içinde bir böcek varsa, kendin yapmak yerine düzeltmelerine izin vermelisin. Sınıfınızın gerçek kullanımı ile test sırasındaki kullanımı arasında farklılık göstermesi gereken tek şey veritabanı bağlantısının parametreleri olmalıdır. Özellik dosyası okuma kodunun, ya da Bahar enjeksiyon mekanizmasının ya da uygulamanızı bir araya getirmek için kullandığınız her şeyin kırılması muhtemel değildir (ve eğer öyleyse, kendiniz düzeltemezsiniz, yukarıya bakın) - bu nedenle kabul edilebilir olduğunu düşünüyorum Bu bit tesisat fonksiyonelliğini test etmek değil.
Kilian Foth

2
@KilianFoth tamamen iş ortamı ve çalışanların rolleriyle ilgilidir. Gerçekten soru ile ilgisi yok. Veritabanından sorumlu hiç kimse yoksa?
Reactgular

Bazı alaycı çerçeveler alay konusu nesnelere, özel ve statik üyelere bile, hemen hemen her şeye enjekte etmenizi sağlar. Bu, sahte db bağlantıları gibi şeylerle test yapmayı çok kolaylaştırır. Mockito + Powermock bugünlerde benim için işe yarıyor (Java, çalışmakta olduğunuzdan emin değiller).
FrustratedWithFormsDesigner

Yanıtlar:


21

Birim testinin amacı, bir sınıfı test etmektir (aslında, genellikle bir yöntemi test etmelidir ).

Bu A, dersleri test ederken , içine kendi kendine yazılmış bir şeyi ya da şimşek çakan bir hafızada veri tabanı olan bir test veritabanını enjekte ettiğiniz anlamına gelir .

Bununla birlikte, Bbir müşterisi olan sınıfı test ederseniz A, o zaman genellikle tüm Anesneyi başka bir şeyle, muhtemelen işini ilkel, önceden programlanmış bir şekilde yapan bir şeyle alay edersiniz - gerçek bir Anesneyi kullanmadan ve kesinlikle bir veri kullanmadan base ( Atüm veri tabanı bağlantısını arayana geri götürmediği sürece - ama bu çok korkunç bir şey düşünmek istemiyorum). Aynı şekilde, Cmüşterisi olan sınıf için bir birim testi yazdığınızda B, rol alan bir şeyle alay eder Bve Atamamen unutursunuz .

Bunu yapmazsanız, artık bir birim testi değil, bir sistem veya entegrasyon testidir. Bunlar da çok önemli, ama tamamen farklı bir su ısıtıcısı. Başlangıç ​​olarak, genellikle kurulum ve çalıştırma için daha fazla çaba harcarlar, onları check-in işlemlerinin bir ön şartı olarak geçirmeyi talep etmek pratik değildir.


11

Veri tabanı bağlantısına karşı birim testleri yapmak tamamen normaldir ve genel bir uygulamadır. puristSisteminizdeki her şeyin bağımlılığın enjekte edilebildiği bir yaklaşım oluşturmak mümkün değildir .

Buradaki anahtar, geçici veya yalnızca test veritabanını test etmek ve bu test veritabanını oluşturmak için mümkün olan en hafif başlatma işlemine sahip olmaktır.

CakePHP'de birim testi için adlandırılan şeyler var fixtures. Fikstür, bir birim testi için anında oluşturulan geçici veritabanı tablolarıdır. Fikstür bunları oluşturmak için uygun yöntemlere sahiptir. Test veritabanındaki bir üretim veritabanından bir şema oluşturabilirler veya basit bir gösterim kullanarak şemayı tanımlayabilirsiniz.

Bununla başarının anahtarı, iş veritabanını uygulamak değil, yalnızca test ettiğiniz kodun yönüne odaklanmaktır. Bir veri modelinin yalnızca yayınlanmış belgeleri okuduğunu doğrulayan bir birim testiniz varsa, o test için tablo şemasında yalnızca bu kod için gereken alanlara sahip olmalıdır. Yalnızca bu kodu test etmek için içerik yönetimi veritabanının tamamını yeniden uygulamanız gerekmez.

Bazı ek referanslar.

http://en.wikipedia.org/wiki/Test_fixture

http://phpunit.de/manual/3.7/en/database.html

http://book.cakephp.org/2.0/en/development/testing.html#fixtures


28
Katılmıyorum. Veri tabanı bağlantısı gerektiren bir test bir birim testi değildir, çünkü doğası gereği testin yan etkileri olacaktır. Bu, otomatik bir test yazamayacağınız anlamına gelmez, ancak böyle bir test, tanımlamanız gereği, sisteminizin alanlarını kod tabanınızın ötesinde kullanan bir entegrasyon testidir.
KeithS

5
Bana saf diyorsun, ama bir birim testinin test çalışma zamanı ortamının "sanal alanını" bırakan herhangi bir eylemde bulunmaması gerektiğine inandım. Veritabanlarına, dosya sistemlerine, ağ soketlerine vb. Dokunmamalılar. Bu, birkaç nedenden ötürü, testin en azından dış duruma bağımlılığı değildir. Başka bir performans; birim test takımınız hızlı bir şekilde çalışmalıdır ve bu harici verilerle etkileşime girme, büyüklük derecelerine göre yavaş testleri saklar. Kendi gelişimimde, depolarım gibi şeyleri test etmek için kısmi alay kullanıyorum ve kum havuzuma bir "kenar" tanımlamakta rahatım.
KeithS

2
@gbjbaanb - İlk başta kulağa hoş geliyor, ama benim tecrübeme göre bu çok tehlikeli. En iyi tasarlanan test takımlarında ve çerçevelerinde bile, bu işlemi geri alma kodu yürütülmeyebilir. Test çalıştırıcısı çökerse veya testin içinde iptal edilirse veya test bir SOE veya OOME atarsa, en iyi durumda askıda bir bağlantıya sahip olursunuz ve DB'de bağlantı kesilene kadar dokunduğunuz masaları kilitleyen işlem gerçekleştirirsiniz. Bunun SQLite'ı test DB'si olarak kullanmak gibi sorunlara yol açmasının önleme yolları, örneğin gerçek DB'yi gerçekten egzersiz yapmamanız gibi, kendi dezavantajlarına sahiptir .
KeithS

5
@KeithS Sanırım anlambilimi tartışıyoruz. Birim testinin tanımının veya bir entegrasyon testinin ne olduğu ile ilgili değil. Veritabanı bağlantısına bağlı olarak kodu test etmek için fikstür kullanıyorum. Bu bir entegrasyon testi ise, bunda iyiyim. Testin geçtiğini bilmem gerekiyor. Bağımlılık, performans veya riskleri umursamıyordum. Bu test geçmediği sürece bu kodun işe yarayıp yaramadığını bilmiyorum. Testlerin çoğunluğu için bağımlılık yoktur, ancak olduğu yerde, o zaman bu bağımlılıklar çözülemez. Olması gerektiğini söylemek kolay, ama basitçe olamazlar.
Reactgular

4
Bence biz de öyleyiz. Entegrasyon testlerim için de "birim test çerçevesi" (NUnit) kullanıyorum, ancak bu iki test kategorisini (genellikle ayrı kütüphanelerde) ayırdığınızdan emin oluyorum. Ben marka çalışıyordu noktadan check Eğer iteratif kırmızı-yeşil-refactor metodoloji takip olarak, böylece o, tamamen izole olmalıdır sizin birim test paketi, bir sen her öncesinde günde birkaç kez çalıştırmak olmasıdır edebilirsiniz koşmak Bunlar, çalışma arkadaşlarınızın ayak parmaklarına basmadan günde birkaç kez test eder.
KeithS

4

Kod tabanınızda bir yerde, uzak DB'ye bağlanma fiili eylemini gerçekleştiren bir kod satırı vardır. Bu kod satırı, 10'da 9 kez, dilinize ve ortamınıza özgü çalışma zamanı kitaplıkları tarafından sağlanan "yerleşik" bir yöntemdir. Bu nedenle, "sizin" kodunuz değildir ve bu nedenle test etmeniz gerekmez; Birim testi için, bu yöntem çağrısının doğru şekilde çalışacağına güvenebilirsiniz. Ünitenizin test takımında hala test edebilecekleriniz ve test etmeniz gerekenler, bu çağrı için kullanılacak parametrelerin sağlanması gibi olmasını beklediğiniz şeylerdir, örneğin bağlantı dizgisinin doğru olduğundan emin olmak veya saklı yordam adı.

Bu, ünite testlerinin çalışma zamanlarını "sanal alanını" terk etmemeleri ve dış duruma bağlı olmalarının kısıtlanmasının ardındaki amaçlardan biridir. Aslında oldukça pratik; Birim testinin amacı, yazdığınız kodun (veya TDD'de yazmak üzere olan) düşündüğünüz gibi davrandığını doğrulamaktır . Yazmadığınız kod, örneğin veritabanı işlemlerinizi gerçekleştirmek için kullandığınız kitaplık, herhangi bir ünite testinin bir parçası olmamalıdır, çünkü yazmamış olmanızın çok basit bir nedeni var.

Senin içinde entegrasyon test paketi, bu kısıtlamaların yapılması hoş karşılanmaz. Şimdi yapabilirsinyazdığınız kodun yapmadığınız kodla iyi çalışmasını sağlamak için veritabanına dokunan testler tasarlayın. Bununla birlikte, bu iki test takımı ayrı tutulmalıdır, çünkü birim test takımınız ne kadar hızlı çalışırsa çalışsın (geliştiriciler tarafından kodları hakkında yapılan tüm iddiaların hala geçerli olduğunu doğrulayabilirsiniz) dış kaynaklara eklenen bağımlılıklar nedeniyle büyüklük sırasına göre daha yavaştır. Build-bot'un tam entegrasyon paketinizi birkaç saatte bir çalıştırmasına izin verin, harici kaynakları kilitleyen testleri uygulayın, böylece geliştiriciler bu aynı testleri yerel olarak uygulayarak birbirlerinin ayaklarına basmazlar. Ve eğer yapı bozulursa, ne olmuş? Yap-bot'un asla bir yapıda başarısız olması gerektiğinden daha fazla başarısız olmamasını sağlamak için çok daha fazla önem verilir.


Şimdi, buna ne kadar sıkı sıkıya bağlı kalabileceğiniz, veritabanına bağlanma ve sorgulama için tam stratejinize bağlıdır. ADO.NET'in SqlConnection ve SqlStatement nesneleri gibi "çıplak kemikleri" veri erişim çerçevesini kullanmanız gereken birçok durumda, sizin tarafınızdan geliştirilen tüm bir yöntem yerleşik yöntem çağrıları ve veritabanı bağlantısı ve bu durumda yapabileceğiniz en iyi şey, tüm işleviyle alay etmek ve entegrasyon test paketlerinize güvenmektir. Ayrıca, sınıflarınızı test amaçlı olarak belirli kod satırlarının değiştirilmesine izin verecek şekilde nasıl tasarlayacağınıza da bağlıdır (Tobi'nin "kısmi alaylara izin verdiği için iyi bir şablon olan Şablon Yöntemi modelinin önerisi gibi)

Veri kalıcılık modeliniz veri katmanınızdaki (tetikleyiciler, depolanan işlemler vb. Gibi) koda dayanıyorsa, yazdığınız kodu egzersiz yapmak için veri katmanının içinde yaşayan ya da kodları aşan testler geliştirmekten başka bir yol yoktur. Çalışma zamanınız ve DBMS arasındaki sınır. Bir temizlikçi, bu nedenle, bu nedenle, bir ORM gibi bir şey lehine kaçınılması gerektiğini söyleyecektir. O kadar ileri gideceğimi sanmıyorum; dile entegre edilmiş sorgular ve diğer derleyici tarafından kontrol edilen, etki alanına bağlı kalıcılık işlemlerinde bile, veritabanını yalnızca saklı yordamla maruz kalan işlemlere kilitlemenin değerini görüyorum ve elbette bu tür saklı yordamlar otomatikleştirilmiş kullanarak doğrulanmalıdır. testleri. Ancak, bu tür testler birim testleri değildir . Onlar entegrasyondur testleri.

Bu ayrımla ilgili bir probleminiz varsa, genellikle "kod kapsamı" aka "birim test kapsamı" konusuna büyük önem verilir. Kodunuzun her satırının bir birim testi tarafından kapsandığından emin olmak istiyorsunuz. Yüzünde asil bir hedef var, ama ben diyorum ki; Bu zihniyet, kendisini uygulayan ancak egzersiz yapmayan iddiasız testler yazmak gibi, bu özel durumun çok ötesine uzanan anti-kalıplara borç verir.senin kodun. Bu tür son çalışmalar yalnızca kapsam sayıları uğruna, minimum kapsamınızı gevşetmekten daha zararlıdır. Kod tabanınızın her satırının bazı otomatik testlerle çalıştırıldığından emin olmak istiyorsanız, bu kolaydır; Kod kapsamı ölçümlerini hesaplarken entegrasyon testlerini dahil edin. Hatta bir adım daha ileri gidebilir ve bu tartışmalı "Itino" testlerini izole edebilirsiniz ("Sadece adında entegrasyon") ve ünite test grubunuz ile bu entegrasyon testlerinin alt kategorisi (hala oldukça hızlı çalışmalıdır) arasına girmeniz gerekir. kapsama alanına yakın.


2

Birim testleri hiçbir zaman bir veritabanına bağlanmamalıdır. Tanım olarak, sisteminizin geri kalanından toplam izolasyonda her birinin tek bir kod birimini (bir yöntem) test etmeleri gerekir. Olmazlarsa, bir birim testi değildirler.

Anlambilim bir yana, bunun faydalı olmasının sayısız nedeni var:

  • Testler, büyüklük sırasını daha hızlı test eder
  • Geri besleme döngüsü anında gerçekleşir (örnek olarak TDD için <1'in geribildirimi)
  • Testler inşa / konuşlandırma sistemleri için paralel olarak yapılabilir
  • Sınamaların çalışması için bir veritabanına gereksinim duymaz (yapıyı çok daha kolay veya en azından daha hızlı hale getirir)

Birim testleri çalışmanızı kontrol etmenin bir yoludur. Belirli bir yöntem için tüm senaryoları ana hatlarıyla belirtmelidirler; bu, genellikle bir yöntem aracılığıyla farklı yolların tümü anlamına gelir. Çift girişli defter tutmaya benzer şekilde inşa ettiğiniz şartnamenizdir.

Tanımladığınız şey başka bir otomatik test türüdür: bir entegrasyon testi. Onlar da çok önemliyken, ideal olarak onlardan çok daha azına sahip olacaksınız. Bir grup birimin birbirleriyle düzgün bir şekilde bütünleştiğini doğrulamalıdırlar.

Peki veritabanına erişimi olan şeyleri nasıl test edersiniz? Tüm veri erişim kodunuz belirli bir katmanda olmalıdır, böylece uygulama kodunuz asıl veritabanı yerine taklit edilebilir servislerle etkileşime girebilir. Bu hizmetlerin herhangi bir SQL veritabanı türü, bellek içi test verileri veya hatta uzak web servis verileri tarafından desteklenmesi umrunda olmamalıdır. Bu onların endişesi değil.

İdeal olarak (ve bu çok özneldir), kodunuzun büyük bölümünü birim testlerinin kapsamına girmesini istersiniz. Bu size her bir parçanın bağımsız olarak çalıştığı konusunda güven verir. Parçalar inşa edildikten sonra bunları bir araya getirmeniz gerekir. Örnek - Kullanıcının şifresini aldığımda, bu kesin çıktıyı almalıyım.

Her bir bileşenin kabaca 5 sınıftan oluştuğunu varsayalım - onların içindeki tüm başarısızlık noktalarını test etmek istersiniz. Bu, her şeyin doğru şekilde kablolandığından emin olmak için çok daha az teste eşittir. Örnek - test kullanıcı bir kullanıcı adı / şifre verilen veritabanından kullanıcıyı bulabilirsiniz.

Son olarak, aslında işletme hedeflerini yerine getirdiğinizden emin olmak için bazı testlerden geçmesini istiyorsunuz. Bunlardan daha az var; uygulamanın çalıştığından ve yapmak için ne yapıldığından emin olduklarından emin olabilirler. Örnek - Bu test verisi verildiğinde, oturum açabilmeliyim.

Bu üç tür testi bir piramit olarak düşünün. Her şeyi desteklemek için birçok birim testine ihtiyacınız var ve sonra oradan yukarı çıkmaya çalışıyorsunuz.


1

İskelet Metodu şablonu yardımcı olabilir.

Çağrıları bir veritabanına protectedyöntemlerle sarın . Bu sınıfı test etmek için, gerçek veritabanı connetion sınıfından miras alan ve korunan yöntemleri geçersiz kılan sahte bir nesneyi test ediyorsunuz.

Bu şekilde veri tabanına yapılan çağrılar asla birim testlerine tabi tutulmaz, doğru. Ama bu sadece birkaç kod satırı. Ve bu kabul edilebilir.


1
Neden kendi soruma cevap verdiğimi merak ediyorsanız: Evet, bu bir cevap olabilir ama doğru olup olmadığından emin değilim.
TobiMcNamobi

-1

Harici verilerle test, entegrasyon testidir. Birim testi, yalnızca birimi test ettiğiniz anlamına gelir. Çoğunlukla iş mantığınızla yapılır. Kod ünitenizi test edilebilir hale getirmek için, ünitenizi kodunuzun diğer bölümlerinden bağımsız hale getirmek zorunda olduğunuz gibi bazı yönergeleri takip etmeniz gerekir. Ünite testi sırasında verilere ihtiyacınız varsa, o zaman bağımlılık enjeksiyonuyla bu verileri zorla enjekte etmeniz gerekir. Orada bazı alaycı ve saplama çerçeve var.

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.