Birim testi C ++: Ne test edilir?


20

TL; DR

İyi, yararlı testler yazmak zordur ve C ++ 'da yüksek bir maliyeti vardır. Deneyimli geliştiriciler neyi ve ne zaman test edeceğinizi gerekçenizi paylaşabilir misiniz?

Uzun Hikaye

Eskiden test odaklı geliştirme yapıyordum, aslında tüm ekibim, ama bizim için iyi çalışmadı. Birçok testimiz var, ancak hiçbir zaman gerçek hatalar ve gerilemelerimiz olan vakaları kapsamıyor gibi görünüyor - genellikle üniteler etkileşime girdiğinde, izole davranışlarından değil.

Bu, birim seviyesinde test etmek o kadar zordur ki, TDD yapmayı bıraktık (gelişimi gerçekten hızlandırdığı bileşenler hariç) ve bunun yerine entegrasyon testi kapsamını artırmak için daha fazla zaman harcadık. Küçük birim testleri hiçbir zaman gerçek bir hata yakalamadı ve temelde sadece bakım yükü olsa da, entegrasyon testleri gerçekten çabaya değerdi.

Şimdi yeni bir proje miras aldım ve nasıl test edeceğimi merak ediyorum. Bu yerel bir C ++ / OpenGL uygulamasıdır, bu nedenle entegrasyon testleri gerçekten bir seçenek değildir. Ancak C ++ 'da birim testi Java (biraz açık bir şekilde şeyler yapmak zorunda virtual) daha zordur ve program ağır nesne odaklı değil, bu yüzden bazı şeyler alay / saplama olamaz.

Sadece test yazma uğruna bazı testler yazmak için her şeyi parçalamak ve OO-boyutlandırmak istemiyorum. Size soruyorum: Testler ne için yazmalıyım? Örneğin:

  • Sık sık değiştirmeyi beklediğim fonksiyonlar / sınıflar?
  • Manuel olarak test edilmesi daha zor olan fonksiyonlar / sınıflar?
  • Test edilmesi kolay fonksiyonlar / sınıflar?

Bazı saygın C ++ kod üslerini nasıl test ettiklerini görmek için araştırmaya başladım. Şu anda Chromium kaynak kodunu arıyorum, ancak test gerekçelerini koddan çıkarmak zor buluyorum. Herkesin popüler C ++ kullanıcılarının (komite mensupları, kitap yazarları, Google, Facebook, Microsoft, ...) buna nasıl yaklaştığına dair iyi bir örneği veya yayını varsa, bu çok yardımcı olacaktır.

Güncelleştirme

Bunu yazdığımdan beri bu sitede ve web'de yolumu araştırdım. Bazı iyi şeyler buldum:

Ne yazık ki, bunların hepsi Java / C # merkezlidir. Java / C # 'da çok sayıda test yazmak büyük bir sorun değildir, bu nedenle fayda genellikle maliyetlerden ağır basar.

Ama yukarıda yazdığım gibi, C ++ 'da daha zor. Özellikle kod tabanınız OO değilse, iyi bir birim test kapsamı elde etmek için işleri ciddi şekilde karıştırmanız gerekir. Örneğin: Devraldığım uygulamanın GraphicsOpenGL üzerinde ince bir katman olan bir ad alanı var. Tüm işlevlerini doğrudan kullanan varlıklardan herhangi birini test etmek için bunu bir arayüze ve sınıfa dönüştürüp tüm varlıklara enjekte etmem gerekir. Bu sadece bir örnek.

Bu soruyu cevaplarken, test yazmak için oldukça büyük bir yatırım yapmam gerektiğini lütfen unutmayın.


3
C ++ birim testindeki zorluk için +1. Birim testiniz kodu değiştirmenizi gerektiriyorsa değiştirmeyin.
DPD

2
@DPD: Pek emin değilim, ya bir şey gerçekten denemeye değerse? Mevcut kod tabanında, neredeyse tüm grafik fonksiyonlarını çağırdığı için simülasyon kodunda hiçbir şeyi test edemiyorum ve onları alay edemiyorum / saplayamıyorum. Şu anda test edebildiğim tek şey yardımcı işlevler. Ama katılıyorum, kodun "test edilebilir" hale getirilmesi yanlış geliyor. TDD taraftarları genellikle bunun tüm kodlarınızı akla gelebilecek her şekilde daha iyi hale getireceğini söylüyor, ama alçakgönüllülükle katılmıyorum. Her şeyin bir arayüze ve çeşitli uygulamalara ihtiyacı yoktur.
futlib

Size son bir örnek vereyim: Bir gün boyunca bir tekli fonksiyonu (C ++ / CLI ile yazılmış) test etmeye çalıştım ve MS Test test aracı her zaman bu test için çökecektir. Düz CPP referanslarıyla ilgili bir sorun var gibi görünüyordu. Bunun yerine, sadece arama işlevinin çıkışını test ettim ve iyi çalıştı. Bir gün UT bir fonksiyona harcadım. Bu değerli zaman kaybıydı. Ayrıca benim ihtiyaçlarına uygun herhangi bir stubbing aracı alamadım. Mümkün olan her yerde manuel saplama yaptım.
DPD

Bu sadece kaçınmak istiyorum şeyler: DI sanırım biz C ++ geliştiricileri özellikle test konusunda pragmatik olmak zorunda. Sonunda test ettin, bu yüzden sanırım sorun değil.
futlib

@DPD: Bununla ilgili biraz daha düşündüm ve bence haklısın, soru ne tür bir ödünleşmek istediğim. Birkaç varlığı test etmek için tüm grafik sistemini yeniden düzenlemeye değer mi? Orada bildiğim bir hata yoktu, bu yüzden muhtemelen: Hayır. Buggy hissetmeye başlarsa, testler yazacağım. Çok kötü Cevabınızı kabul edemem çünkü bu bir yorum :)
futlib

Yanıtlar:


5

Birim Testi sadece bir bölümdür. Entegrasyon testleri ekibinizin problemi konusunda size yardımcı olur. Entegrasyon Testleri, yerel ve OpenGL uygulamaları için de her türlü uygulama için yazılabilir. Steve Freemann ve Nat Pryce (örneğin, http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627 ) tarafından "Testlerle Yönlendirilen Büyüyen Nesne Odaklı Yazılımlar" ı kontrol etmelisiniz . GUI ve ağ iletişimi ile bir uygulamanın geliştirilmesinde adım adım yol gösterir.

Test Test edilmeyen yazılımlar başka bir hikaye. Michael Feathers'a "Eski Kodla Etkili Çalışma" (http://www.amazon.com/Working-Efftively-Legacy-Michael-Feathers/dp/0131177052) adresini ziyaret edin.


Her iki kitabı da biliyorum. Olaylar şunlardır: 1. TDD ile birlikte gitmek istemiyoruz, çünkü bizimle iyi çalışmadı. Testler istiyoruz, ama dini olarak değil. 2. OpenGL uygulamaları için entegrasyon testlerinin bir şekilde mümkün olduğundan eminim, ancak çok fazla çaba gerektiriyor. Bir araştırma projesi başlatmak değil, uygulamayı geliştirmeye devam etmek istiyorum.
futlib

Kodun test edilebilir (yeniden kullanılabilir, bakımı yapılabilir vb.) Olacak şekilde tasarlanmadığı için, "gerçeği takiben" birim testinin her zaman "önce test et" den daha zor olduğunu unutmayın. Yine de yapmak istiyorsanız, TDD'den kaçınsanız bile Michael Feathers hilelerine (örneğin dikişlere) bağlı kalmaya çalışın. Örneğin, bir işlevi genişletmek istiyorsanız, "filiz yöntemi" gibi bir şey deneyin ve yeni yöntemi test edilebilir tutmaya çalışın. IMHO yapmak mümkün ama daha zor.
EricSchaefer

TDD olmayan kodun test edilebilir olarak tasarlanmadığını kabul ediyorum, ancak kendiliğinden sürdürülemez veya tekrar kullanılamaz olduğunu söyleyemem - yukarıda yorumladığım gibi, bazı şeylerin sadece arayüzlere ve çoklu uygulamalara ihtiyacı yoktur. Mockito ile hiç sorun değil, ama C ++, sanal / stub alay etmek istediğim tüm işlevleri yapmak gerekir. Her neyse, test edilemeyen kod şu anda benim en büyük sorunum: Bazı parçaları test edilebilir yapmak için bazı temel şeyleri değiştirmek zorundayım ve bu yüzden buna değeceğinden emin olmak için neyin test edileceğine dair iyi bir mantık istiyorum.
futlib

Tabii ki haklısın, test edebileceğim yeni kodlar oluşturmaya dikkat edeceğim. Ancak, işlerin bu kod tabanında çalışma şekli şu anda kolay olmayacak.
futlib

Bir özellik / işlev eklerken, onu nasıl test edebileceğinizi düşünün. Çirkin bağımlılıklar enjekte edebilir misiniz? Fonksiyonun yapması gereken şeyi yaptığını nasıl bilebilirsiniz? Herhangi bir davranış gözlemleyebilir misiniz? Doğruluğunu kontrol edebileceğiniz herhangi bir sonuç var mı? Kontrol edebileceğiniz değişmezler var mı?
EricSchaefer

2

TDD "sizin için iyi çalışmadı." Sanırım nereye döneceğimi anlamanın anahtarı bu. TDD'nin nasıl çalışmadığını, neyi daha iyi yapabilirdiniz, neden zorluk yaşandığını tekrar gözden geçirin ve anlayın.

Tabii ki, birim testleriniz bulduğunuz hataları yakalamadı. Mesele bu. :-) Bu hataları bulamadınız çünkü arayüzlerin nasıl çalışması gerektiği ve düzgün bir şekilde test edildiğinden nasıl emin olunacağını düşünerek ilk etapta gerçekleşmelerini engellediniz.

Cevaplamak için, sorduğunuz gibi, test edilecek tasarım olmayan birim test kodunun zor olduğunu soruyorsunuz. Mevcut kod için, bir birim test ortamından ziyade bir işlevsel veya entegrasyon test ortamının kullanılması daha etkili olabilir. Sistemi belirli alanlara odaklanarak genel olarak test edin.

Tabii ki yeni gelişme TDD'den faydalanacak. Yeni özellikler eklendikçe, TDD için yeniden düzenleme yeni gelişimi test etmeye yardımcı olurken, eski işlevler için yeni birim testinin geliştirilmesine de yardımcı olabilir.


4
TDD'yi yaklaşık bir buçuk yıl boyunca yaptık, hepsi oldukça tutkulu. Ancak TDD projelerini TDD olmadan yapılan (ancak testler olmadan) daha önceki projelerle karşılaştırarak, aslında daha kararlı olduklarını veya daha iyi tasarlanmış kodlara sahip olduklarını söyleyemem. Belki de bizim ekibimiz: Çok eşleştiriyoruz ve inceliyoruz, kod kalitemiz her zaman oldukça iyi oldu.
futlib

1
Ne kadar çok düşünürsem, TDD'nin o projenin teknolojisine pek uymadığını düşünüyorum: Flex / Swiz. Nesneler arasındaki etkileşimleri karmaşık ve birim testi yapmak neredeyse imkansız hale getiren birçok olay, cilt ve enjeksiyon devam ediyor. Bu nesneleri ayırmak onu daha iyi yapmaz, çünkü ilk etapta doğru çalışırlar.
futlib

2

C ++ TDD yapmadım bu yüzden bu konuda yorum yapamam, ama kodunuzun beklenen davranışını test etmek gerekiyor. Uygulama değişebilse de, davranış (genellikle?) Aynı kalmalıdır. Java \ C # merkezli dünyada bu, yalnızca genel yöntemleri test ettiğiniz, beklenen davranış için testler yazdığınız ve uygulamadan önce yaptığınız anlamına gelir (genellikle yapılmasından daha iyi söylenir :)).

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.