Birim testi erken genellemeye yol açar mı (özellikle C ++ bağlamında)?


20

Ön notlar

Farklı test türlerinin ayrımına girmeyeceğim, var zaten birkaç soru olduğunu dair bu sitelerde.

Ne var ve diyor alacağım: birimi "bir uygulamanın en küçük izole birimini test" anlamında test hangi Bu soru aslında türemiştir gelen

İzolasyon sorunu

Nedir Bir programın en küçük izole edilebilir birimi . Gördüğüm kadarıyla, hangi dilde kodladığınıza bağlı.

Micheal Feathers bir dikiş kavramı hakkında konuşuyor : [WEwLC, s31]

Bir dikiş, o yerde düzenleme yapmadan programınızdaki davranışı değiştirebileceğiniz bir yerdir.

Ve ayrıntılara girmeden, “test” inizin “biriminiz” ile arayüz oluşturabileceği bir programda yer almak için - birim testi bağlamında - bir dikiş anlıyorum.

Örnekler

Birim testi - özellikle C ++ 'da - belirli bir sorun için kesinlikle çağrılacak daha fazla dikiş eklemek için test edilen koddan gereklidir.

Örnek:

  • Sanal olmayan uygulamanın yeterli olacağı bir sanal arabirim ekleme
  • Bölme - genelleme (?) - bir (ufacık) sınıf daha ileri "sadece" bir test eklemeyi kolaylaştırmak için.
  • Testler için bağımsız olarak derlenmelerini kolaylaştırmak amacıyla, tek yürütülebilir projenin görünüşte "bağımsız" kütüphanelere bölünmesi "sadece".

Soru

Umarım aynı noktayı soran birkaç sürümü deneyeceğim:

  • Birim Testleri, bir uygulamanın kodunu birim testleri için "sadece" yapılandırmasını gerektiriyorsa veya aslında uygulama yapısına faydalı mıdır?
  • Tabi kod genelleme birim-test edilebilir bir şey için kullanışlı hale getirmek için mi ama ünite testleri?
  • Birim testleri eklemek, birini gereksiz yere genellemeye zorlar mı?
  • Şekil birimi testleri kod üzerinde "her zaman" da zorlanıyor, genel olarak sorun alanından da görüldüğü gibi kod için iyi bir şekil mi?

Kodu kullanan ikinci bir yer olana kadar genelleme yapmadığını söyleyen bir başparmak kuralını hatırlıyorum. Birim Testleri ile her zaman kodu kullanan ikinci bir yer vardır - birim testi. Peki bu sebep genelleme için yeterli mi?


8
Yaygın bir meme, herhangi bir paternin anti-patern haline gelmesi için aşırı derecede kullanılabileceğidir. Aynı durum TDD için de geçerlidir. Test edilen kodun eklenen genelleştirilmiş test arayüzlerinden daha az olduğu ve çok düşük maliyet-fayda alanına, azalan getiri noktasının ötesinde test edilebilir arayüzler eklenebilir. Derin uzay görevi OS gibi test etmek için ek arayüzlere sahip sıradan bir oyun, piyasa penceresini tamamen kaçırabilir. Eklenen testin bu bükülme noktalarından önce olduğundan emin olun.
hotpaw2

@ hotpaw2 Küfür! :)
maple_shaft

Yanıtlar:


23

Birim testi - özellikle C ++ 'da - belirli bir sorun için kesinlikle çağrılacak daha fazla dikiş eklemek için test edilen koddan gereklidir.

Sadece problem çözmenin ayrılmaz bir parçasını test etmeyi düşünmüyorsanız. Herhangi bir önemsiz sorun için, sadece yazılım dünyasında değil.

Donanım dünyasında, bu uzun zaman önce - zor yoldan öğrenildi. Çeşitli ekipman üreticileri yüzyıllar boyunca sayısız düşen köprülerden, patlayan arabalardan, sigara içen CPU'lardan vb. Hepsi, test edilebilir hale getirmek için ürünlerine "ekstra dikişler" oluşturur. Günümüzde çoğu yeni otomobil, tamircilerin motorda neler olduğu hakkında veri almaları için teşhis portlarına sahiptir. Her CPU üzerindeki transistörlerin önemli bir kısmı teşhis amaçlıdır. Donanım dünyasında, her "ekstra" malzeme maliyeti ve bir ürün milyonlarca kişi tarafından üretildiğinde, bu maliyetler kesinlikle büyük miktarlarda para ekler. Yine de, üreticiler bu parayı test edilebilirlik için harcamak istiyorlar.

Yazılım dünyasına geri dönersek, C ++, dinamik sınıf yüklemesi, yansıma vb. İçeren daha sonraki dillerden birim testi yapmaktan daha zordur. Yine de, sorunların çoğu en azından hafifletilebilir. Birim testleri kullandığım bir C ++ projesinde, testleri bir Java projesinde yaptığımız kadar sık ​​çalıştırmadık - ama yine de CI derlememizin bir parçasıydık ve onları faydalı bulduk.

Birim Testlerinin bir kişinin kodunu "sadece" yapılandırması, birim testler için faydalı mıdır, yoksa aslında uygulama yapısına faydalı mıdır?

Deneyimlerime göre test edilebilir bir tasarım genel olarak yararlıdır, ünite testleri için "sadece" değil. Bu faydalar farklı düzeylerde gelir:

  • Tasarımınızı test edilebilir yapmak, uygulamanızı birbirini yalnızca sınırlı ve iyi tanımlanmış şekillerde etkileyebilecek küçük, daha fazla veya daha az bağımsız parçalara ayırmanızı sağlar - bu, programınızın uzun vadeli istikrarı ve sürdürülebilirliği için çok önemlidir. Bu olmadan kod, kod tabanının herhangi bir bölümünde yapılan herhangi bir değişikliğin programın görünüşte ilgisiz, farklı kısımlarında beklenmedik etkilere neden olabileceği spagetti koduna dönüşme eğilimindedir. Söylemeye gerek yok ki, her programcının kabusu.
  • Testleri TDD tarzında kendileri yazmak aslında API'lerinizi, sınıflarınızı ve yöntemlerinizi kullanır ve tasarımınızın mantıklı olup olmadığını tespit etmek için çok etkili bir test görevi görür - eğer testler ve arayüze karşı yazma testleri garip veya zor geliyorsa, değerli bir erken geri bildirim alırsınız API'yı şekillendirmek hala kolay. Başka bir deyişle, bu sizi API'larınızı erken yayınlamaktan korur.
  • TDD tarafından uygulanan geliştirme modeli, yapılacak somut görev (ler) e odaklanmanıza yardımcı olur ve sizi hedefte tutar, ihtiyaç duyduğunuzdan başka problemleri çözme şansınızı en aza indirir, gereksiz ekstra özellikler ve karmaşıklık ekler , vb.
  • Birim testlerinin hızlı geri bildirimi, kodu yeniden düzenlemede cesur olmanızı sağlar, böylece kodun ömrü boyunca tasarımı sürekli olarak uyarlamanıza ve geliştirmenize olanak tanır, böylece kod entropisini etkili bir şekilde önler.

Kodu kullanan ikinci bir yer olana kadar genelleme yapmadığını söyleyen bir başparmak kuralını hatırlıyorum. Birim Testleri ile her zaman kodu kullanan ikinci bir yer vardır - birim testi. Peki bu sebep genelleme için yeterli mi?

Yazılımınızın tam olarak yapılması gerekeni yaptığını kanıtlayabilir ve birim testleri ile zorlanan "ekstra" genelleme veya dikişler olmadan müşterilerinizi tatmin edecek kadar hızlı, tekrarlanabilir, ucuz ve belirleyici bir şekilde kanıtlarsanız, bunu deneyin (ve bunu nasıl yaptığınızı bize bildirin, çünkü bu forumdaki birçok insanın benim kadar ilgi duyacağından eminim :-)

Btw "genelleme" ile tek bir somut sınıf yerine bir arayüz (soyut sınıf) ve polimorfizm tanıtmak gibi şeyleri kastediyorum - değilse, açıklığa kavuşturun.


Efendim, selamlıyorum.
GordonM

Kısa ama bilgiçlikle ilgili bir not: “teşhis limanı” çoğunlukla oradadır çünkü hükümetler emisyon kontrol planının bir parçası olarak bu yetkileri zorunlu kılmıştır. Sonuç olarak, ciddi sınırlamaları vardır; potansiyel olarak bu port ile teşhis edilebilen pek çok şey vardır (yani emisyon kontrolü ile ilgili olmayan herhangi bir şey).
Robert Harvey

4

Ben atacağım Testivus Way sana, ama özetlemek için:

Kodunuzu sistemin tek bir parçasını test etmek için daha karmaşık hale getirmek için çok fazla zaman ve enerji harcıyorsanız, yapınız yanlış olabilir veya test yaklaşımınız yanlış olabilir.

En basit kılavuz şudur: Test ettiğiniz şey, kodunuzun sistemin diğer bölümleri tarafından kullanılması amaçlanan genel arayüzüdür.

Testleriniz uzun ve karmaşık hale geliyorsa, genel arayüzü kullanmanın zor olacağını gösterir.

Sınıfınızın şu anda kullanılacak tek örneği dışında herhangi bir şey tarafından kullanılmasını sağlamak için miras kullanmanız gerekiyorsa, sınıfınızın kullanım ortamına çok fazla bağlı olması için iyi bir şans vardır. Bunun doğru olduğu bir duruma bir örnek verebilir misiniz?

Ancak, birim test dogmasına dikkat edin. İstemcinin size bağırmasına neden olacak sorunu tespit etmenizi sağlayan testi yazın .


Aynı şeyi ekleyecektim: bir api yap, api'yi test et, dışarıdan.
Christopher Mahan

2

TDD ve Birim Testi, sadece birim testleri için değil, bir bütün olarak program için iyidir. Bunun nedeni beyin için iyi olmasıdır.

Bu, RobotLegs adlı belirli bir ActionScript çerçevesi hakkında bir sunumdur. Bununla birlikte, ilk 10 slayttan geçerseniz, beynin iyi kısımlarına ulaşmaya başlar.

TDD ve Birim testi, beynin bilgiyi işlemesi ve hatırlaması için daha iyi bir şekilde davranmaya zorlar. Önünüzdeki tam göreviniz daha iyi bir birim testi yapmak veya kodu daha fazla birim test edilebilir yapmak olsa da ... aslında yaptığı kodunuzu daha okunabilir yapmak ve böylece kodunuzu daha sürdürülebilir hale getirmektir. Bu, tavşanlarda daha hızlı kodlama yapmanızı sağlar ve özellikler eklemeniz / kaldırmanız, hataları düzeltmeniz veya genel olarak kaynak dosyayı açmanız gerektiğinde kodunuzu daha hızlı anlamanıza olanak tanır.


1

bir uygulamanın en küçük izole edilebilir biriminin test edilmesi

bu doğrudur, ancak çok fazla alırsanız size çok fazla vermez ve maliyeti çok fazladır ve bence bu TDD'nin TDD'nin olması gereken şey olması için BDD'nin kullanımını teşvik eden yönünün bu olduğuna inanıyorum. boyunca - en küçük izole edilebilir birim olmasını istediğiniz şeydir.

Örneğin, bir keresinde (diğer bitler arasında) 2 yöntemi olan bir ağ sınıfında hata ayıkladım: 1 IP adresini ayarlamak için, diğeri bağlantı noktası numarasını ayarlamak için. Doğal olarak, bunlar çok basit yöntemlerdi ve en önemsiz testi kolayca geçecekti, ancak bağlantı noktası numarasını ayarlayıp daha sonra ip adresini ayarlarsanız, çalışma başarısız olur - ip ayarlayıcı, varsayılan olarak bağlantı noktası numarasının üzerine yazıyordu. Bu yüzden, doğru davranışı sağlamak için sınıfı bir bütün olarak test etmek zorundaydınız, sanırım TDD kavramı eksik ama BDD size veriyor. Genel uygulamanın en mantıklı ve en küçük alanını - bu durumda ağ sınıfını - test edebildiğiniz her küçük yöntemi test etmeniz gerekmez.

Sonuçta test için sihirli bir mermi yoktur, sınırlı test kaynaklarınızı ne kadar ve hangi ayrıntıya uygulayacağınız konusunda mantıklı kararlar vermelisiniz. Sizin için otomatik olarak taslaklar oluşturan araç tabanlı yaklaşım bunu yapmaz, künt bir kuvvet yaklaşımıdır.

Bu nedenle, kodunuzu TDD'ye ulaşmak için belirli bir şekilde yapılandırmanıza gerek yoktur, ancak elde ettiğiniz test seviyesi kodunuzun yapısına bağlı olacaktır - eğer tüm mantığı sıkıca bağlı olan monolitik GUI'niz varsa GUI yapısı, o zaman bu parçaları izole etmek daha zor olacak, ama yine de 'birim' GUI anlamına gelir ve tüm arka uç DB çalışmaları alaycı bir birim testi yazabilirsiniz. Bu aşırı bir örnektir, ancak yine de otomatik test yapabileceğinizi gösterir.

Daha küçük birimleri test etmeyi kolaylaştırmak için kodunuzu yapılandırmanın bir yan etkisi, uygulamayı daha iyi tanımlamanıza yardımcı olur ve bu da parçaları daha kolay değiştirmenizi sağlar. Ayrıca kodlama yaparken, 2 geliştiricinin herhangi bir zamanda aynı bileşen üzerinde çalışması daha az muhtemel olacaktır - diğer herkesin çalışmalarını kıran bağımlılıklara sahip olan monolitik bir uygulamanın aksine, birleşme zamanı gelir.


0

Dil tasarımındaki ödünleşimler hakkında iyi bir kavrayışa ulaştınız. C ++ 'daki (statik işlev çağrı mekanizmasıyla karıştırılan sanal işlev mekanizması) bazı temel tasarım kararları TDD'yi zorlaştırır. Dil, kolaylaştırmak için ihtiyacınız olanı gerçekten desteklemiyor. Birim testi yapmak neredeyse imkansız olan C ++ yazmak kolaydır.

TDD C ++ kodumuzu yordamlar değil, yarı işlevsel bir zihniyet yazma işlevlerinden (argüman almayan ve geçersiz döndüren bir işlev) yapıyor ve mümkün olduğunca kompozisyon kullanıyoruz. Bu üye sınıflarını değiştirmek zor olduğundan, bu sınıfları güvenilir bir temel oluşturmak için test etmeye odaklanıyoruz ve daha sonra başka bir şeye eklediğimizde temel ünitenin çalıştığını biliyoruz.

Anahtar yarı fonksiyonel yaklaşımdır. Bir düşünün, tüm C ++ kodunuz global olmayan erişime sahip ücretsiz işlevler olsaydı, bu birim testine bir çırpıda olurdu :)

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.