Özel yöntemleri mi yoksa yalnızca herkese açık olanları mı test etmeliyim? [kapalı]


348

Özel yöntemlerin nasıl test edileceği hakkında bu yazıyı okudum . Genellikle onları test etmiyorum, çünkü her zaman sadece nesnenin dışından çağrılacak genel yöntemleri test etmenin daha hızlı olduğunu düşündüm. Özel yöntemleri test ediyor musunuz? Onları her zaman test etmeli miyim?



"Özel yardımcıları test etmeli miyim?" Evet. "Özel yardımcıları doğrudan test etmeli miyim?" Genel arayüz aracılığıyla kolayca test edebiliyorsanız, neden doğrudan test edebilirsiniz? Yardımcı bir arayüz üzerinden yardımcıların tüm yönlerini test etmek karmaşıklaşırsa, bileşen varlığını tek bir birim olarak geride bıraktı mı?
Mihai Danila

Yanıtlar:


328

Özel yöntemleri tek tek test etmiyorum. Özel yöntem, sınıfın kullanıcılarına gizlenmesi gereken bir uygulama ayrıntısıdır. Özel yöntemlerin test edilmesi kapsüllemeyi keser.

Özel yöntemin kendi testlerini gerektirecek kadar büyük veya karmaşık veya önemli olduğunu fark edersem, başka bir sınıfa koyup orada herkese açık hale getiririm ( Yöntem Nesnesi ). O zaman, artık kendi sınıfında yaşayan özel-ama-şimdi-halka açık yöntemi kolayca test edebilirim.


88
Katılmıyorum. İdeal olarak, bir fonksiyonu kodlamaya başlamadan önce hızlı bir test yazarsınız. Tipik girdiyi ve çıktının ne olacağını düşünün. Testi yazın (ki bu sizi birkaç saniyeden uzun sürmemelidir) ve testi doğru olana kadar kodlayın. Özel yöntemler için bu çalışma tarzından vazgeçmek için hiçbir neden yoktur.
Frank

254
Özel yöntemlerin teste ihtiyacı olmadığını söylemek, bir arabanın iyi sürdüğü sürece iyi olduğunu ve kaputun altında ne olduğu önemli olmadığını söylemek gibidir. Ancak, kullanıcı bir şey fark etmese bile içerideki bir kablonun gevşemeye başladığını bilmek hoş olmaz mıydı? Elbette, her şeyi herkese açık yapabilirsiniz, ama amaç ne? Her zaman bazı özel yöntemler isteyeceksiniz.
Frank

37
"Özel yöntem, sınıfın kullanıcılarına gizlenmesi gereken bir uygulama ayrıntısıdır." ancak testler gerçekten sınıf arayüzünün "normal" (çalışma zamanı) kullanıcılarıyla aynı tarafta mı? ;)
mlvljr

34
Test etmek istediğiniz herhangi bir şeyi başka bir sınıfa çekmenin tehlikesi, ürününüzün aşırı mühendislik yükü ve asla tekrar kullanılmayan bir milyon yeniden kullanılabilir bileşene sahip olmanızdır.
occulus

44
Bir kod parçasını bir araba ile karşılaştırmak yanlıştır; kod zamanla ' kötü gitmez ', sonsuzdur . Genel arabirimi sınamanız yalnızca 'iyi göründüğünü ' belirleyecek kadar ileri giderse , genel kodu sınamanız yeterli olmaz. Bu durumda, özel yöntemleri ayrı ayrı test etmek, ne kadar çok denerseniz deneyin genel testi tamamlamaz. Doğru senaryoları oluşturmak için kodun dahili çalışma bilgisini kullanarak genel kodunuzu bir bütün olarak kapsamlı bir şekilde test etmeye odaklanın.
rustyx

293

Testin amacı nedir?

Şimdiye kadar cevapların çoğu, özel yöntemlerin, kamu arayüzü iyi test edilmiş ve çalışıyor olduğu sürece önemli olmayan (veya en azından olmamalı) uygulama detayları olduğunu söylüyor. Test için tek amacınız ortak arayüzün çalışmasını garanti etmekse bu kesinlikle doğrudur .

Şahsen, kod testleri için birincil kullanımım, gelecekteki kod değişikliklerinin sorun yaratmamasını sağlamak ve eğer yaparlarsa hata ayıklama çabalarıma yardımcı olmaktır. Özel yöntemlerin, kamu arayüzü (daha fazla değilse!) Kadar kapsamlı bir şekilde test edilmesinin bu amacı daha da artırdığını düşünüyorum.

Dikkate alın: Özel yöntem B'yi çağıran genel yöntem A'ya sahipsiniz. A ve B'nin her ikisi de C yöntemini kullanır. Özel olsa da B için test yaptırmak yararlı olmaz mıydı, böylelikle sorunun A'nın C'yi mi, B'nin C'yi mi kullanacağını veya her ikisini birden mi bildiğinizi biliyor musunuz?

Özel yöntemlerin test edilmesi, genel arayüzün test kapsamının eksik olduğu durumlarda da değer katar. Bu genellikle kaçınmak istediğimiz bir durum olsa da, verimlilik birimi testi, hem hataları bulan testlere hem de bu testlerin ilgili geliştirme ve bakım maliyetlerine bağlıdır. Bazı durumlarda,% 100 test kapsamının faydaları, bu testlerin maliyetlerini garanti etmek için yetersiz olarak değerlendirilebilir ve bu da genel arayüzün test kapsamında boşluklar oluşturur. Bu gibi durumlarda, özel bir yöntemin iyi hedeflenmiş bir testi, kod tabanına çok etkili bir ek olabilir.


72
Buradaki sorun şu ki, bu "gelecekteki kod değişiklikleri" her zaman bir sınıfın iç işleyişini yeniden düzenlemek anlamına geliyor. Bu çok sık olur, yazma testleri yeniden düzenleme için bir engel oluşturur.
Yasadışı Programcı

40
Ayrıca, birim testlerinizi sürekli olarak değiştiriyorsanız, testinizdeki tüm tutarlılığı kaybettiniz ve hatta birim testlerinin kendisinde hatalar oluşturabilirsiniz.
17 of 26

6
@ 17 Testler ve uygulama eşzamanlı olarak değiştirilirse (göründüğü gibi olması gerekir), çok daha az sorun olacaktır.
mlvljr


3
@Pacerier Kodunuzu test etmek ile sürekli otomatik test sürecine sahip olmak arasında bir fark vardır. Özel yönteminizin çalıştığından emin olmalısınız, ancak yazılımın kullanım durumunun bir parçası olmadığı için sizi özel yönteme bağlayan testler yapmamalısınız.
Didier A.

150

Pragmatik Birim Testi adlı kitabında Dave Thomas ve Andy Hunt'ın tavsiyelerine uyma eğilimindeyim :

Genel olarak, test uğruna herhangi bir kapsülleme koparmak istemezsiniz (ya da annemin eskiden "ayrıcalıklarınızı ifşa etmeyin!"). Çoğu zaman, bir sınıfı genel yöntemlerini kullanarak test edebilmelisiniz. Özel veya korumalı erişimin arkasında gizlenmiş önemli bir işlevsellik varsa, bu, orada çıkmak için mücadele eden başka bir sınıfın olduğunu gösteren bir uyarı işareti olabilir.

Ama bazen kendimi özel yöntemleri test etmekten alıkoyamıyorum çünkü bana tamamen sağlam bir program oluşturduğumun verdiği güven duygusu veriyor .


9
Özel yöntemleri hedefleyen birim testlerini devre dışı bırakmanızı öneririm. Bir kod bağlantısıdır ve gelecekteki yeniden düzenleme çalışmalarına yükler, hatta bazen özellik ekleme veya değiştirme işlemlerini engellerler. Onları uygularken onlar için bir test yazmak iyidir, uygulama çalışmalarınızı kanıtlamanın otomatik bir yolu olarak, ancak testleri regresyon olarak tutmak yararlı değildir.
Didier A.

61

Projemizdeki en son KG önerimizden birini giderek daha fazla takip ettiğim için özel işlevleri test etmeye mecbur hissediyorum:

Fonksiyon başına siklomatik karmaşıklıkta 10'dan fazla olmamalıdır .

Şimdi bu politikanın uygulanmasının yan etkisi, benim çok büyük kamusal işlevlerimin birçoğunun daha odaklanmış, daha iyi adlandırılmış özel işlevlere bölünmesidir .
Kamusal işlev hala orada (elbette) ama aslında tüm bu özel 'alt işlevler' olarak adlandırıldı

Bu gerçekten havalı, çünkü çağrı yerinin okunması artık çok daha kolay (büyük bir işlev içindeki bir hata yerine, anlamamı sağlamak için çağrıdaki önceki işlevlerin adıyla bir alt alt işlevde bir hata var 'oraya nasıl geldim')

Ancak, doğrudan bu özel işlevleri etmek ve büyük kamu işlevinin testini, bir senaryonun ele alınması gereken bir tür 'entegrasyon' testine bırakmak .

Sadece 2 sentim.


2
@jop'a tepki vermek için, bu özel fonksiyonları (büyük, çok siklomatik karmaşık bir kamu fonksiyonunun bölünmesi nedeniyle yaratılmış) başka bir sınıfa ihraç etme ihtiyacını hissetmiyorum. Aynı sınıfta hala kamusal işleve sıkı sıkıya bağlı olmalarını seviyorum. Ama yine de birim test edildi.
VonC

2
Benim deneyimlerim, bu özel yöntemlerin sadece bu genel yöntemlerle yeniden kullanılan yarar yöntemi olduğudur. Bazen orijinal sınıfı iki (veya üç) daha uyumlu sınıfa ayırmak, bu özel yöntemleri kendi sınıflarında herkese açık hale getirmek ve dolayısıyla test edilebilir hale getirmek daha uygundur.
jop

7
hayır, benim durumumda, bu yeni özel işlevler gerçekten kamu işlevi tarafından temsil edilen daha büyük algoritmanın bir parçasıdır. Bu işlev, faydalı olmayan, ancak daha büyük bir sürecin adımları olan daha küçük parçalara bölünür. Bu nedenle, bunları birim test etme ihtiyacı (tüm algoyu bir kerede birim test etmek yerine)
VonC

Siklomatik karmaşıklıkla ilgilenenler için, konuya bir soru ekledim: stackoverflow.com/questions/105852/…
VonC

Hata! Başlığın yazım hatası nedeniyle sorunun URL'si değişti! stackoverflow.com/questions/105852/…
VonC

51

Evet, özel işlevleri test ediyorum, çünkü genel yöntemlerinizle test edilmelerine rağmen, uygulamanın en küçük bölümünü test etmek TDD'de (Test Tahrikli Tasarım) güzel. Ancak özel birim işlevlerine, test birimi sınıfınızdayken erişilemez. İşte özel yöntemlerimizi test etmek için yaptıklarımız.

Neden özel yöntemlerimiz var?

Özel fonksiyonlar esas olarak sınıfımızda mevcuttur, çünkü genel yöntemlerimizde okunabilir kod oluşturmak istiyoruz. Bu sınıftaki kullanıcının bu yöntemleri doğrudan çağırmasını istemiyoruz, ancak genel yöntemlerimizle. Ayrıca, sınıfı (korumalı olması durumunda) genişletirken davranışlarını değiştirmek istemiyoruz, bu yüzden özeldir.

Kodladığımızda, test odaklı tasarım (TDD) kullanıyoruz. Bu, bazen özel ve test etmek isteyen bir işlevsellik parçasına rastladığımız anlamına gelir. Özel işlevler phpUnit içinde test edilemez, çünkü Test sınıfında bunlara erişemeyiz (özeldir).

Burada 3 çözüm olduğunu düşünüyoruz:

1. Herkese açık yöntemlerinizle ayrıcalıklarınızı test edebilirsiniz

Avantajları

  • Basit birim testi ('kesmek' gerekmez)

Dezavantajları

  • Programcının genel yöntemi anlaması gerekirken, yalnızca özel yöntemi test etmek ister
  • Uygulamanın test edilebilir en küçük kısmını test etmiyorsunuz

2. Eğer özel kişi çok önemliyse, bunun için belki de yeni bir ayrı sınıf yaratmak bir kodlayıcıdır

Avantajları

  • Bunu yeni bir sınıfa yeniden düzenleyebilirsiniz, çünkü eğer bu önemliyse, diğer sınıfların da buna ihtiyacı olabilir
  • Test edilebilir birim artık herkese açık bir yöntemdir, bu yüzden test edilebilir

Dezavantajları

  • Gerekmiyorsa ve yalnızca yöntemin geldiği sınıf tarafından kullanılan bir sınıf oluşturmak istemezsiniz.
  • Ek yük nedeniyle potansiyel performans kaybı

3. Erişim değiştiriciyi (son) korumalı olarak değiştirin

Avantajları

  • Uygulamanın test edilebilir en küçük kısmını test ediyorsunuz. Son korumalı kullanırken, işlev geçersiz kılınmayacaktır (tıpkı özel gibi)
  • Performans kaybı yok
  • Ek yük yok

Dezavantajları

  • Korunanlara özel erişimi değiştiriyorsunuz, yani çocuklar tarafından erişilebilir
  • Kullanabilmek için test sınıfınızda hala bir Mock sınıfına ihtiyacınız var

Misal

class Detective {
  public function investigate() {}
  private function sleepWithSuspect($suspect) {}
}
Altered version:
class Detective {
  public function investigate() {}
  final protected function sleepWithSuspect($suspect) {}
}
In Test class:
class Mock_Detective extends Detective {

  public test_sleepWithSuspect($suspect) 
  {
    //this is now accessible, but still not overridable!
    $this->sleepWithSuspect($suspect);
  }
}

Böylece test birimimiz şimdi eski özel fonksiyonumuzu test etmek için test_sleepWithSuspect'i arayabilir.


eddy147, korumalı yöntemleri alay yoluyla test etme kavramını gerçekten çok seviyorum. Teşekkürler!!!!
Theodore R. Smith

15
Sadece TDD'nin orijinal açıklamasında, birim testinde, ünitenin bir yöntem / işlev değil , sınıf olduğunu belirtmek isterim . Dolayısıyla, "uygulamanın en küçük kısmını test etmek" ten bahsettiğinizde, test edilebilir en küçük kısmı yöntem olarak belirtmek yanlıştır . Bu mantığı kullanırsanız, tüm kod bloğu yerine tek bir kod satırından bahsediyor olabilirsiniz.
Matt Quigley

@Matt Bir iş birimi bir sınıfa değil, aynı zamanda tek bir yönteme de işaret edebilir.
eddy147

4
@ eddy147 Ünite testi, ünitenin bir sınıf olarak tanımlandığı Test Tahrikli Gelişim ile birlikte gelir. Internets'te olduğu gibi, anlambilim bir çok şey anlamına geldi (yani 2 kişiye birim ve entegrasyon testi arasındaki farkın ne olduğunu sorun ve 7 cevap alırsınız). TDD, bir sınıfın tek bir sorumluluğu olduğu ve yüksek bir döngüsel karmaşıklığa sahip olmaması gereken Tek Sorumluluk da dahil olmak üzere SOLID ilkeleri ile yazılım yazmanın bir yoluydu. TDD'de sınıfınızı yazıyor ve her iki üniteyi birlikte test ediyorsunuz. Özel yöntemler kapsüllenmiştir, karşılık gelen birim testi yoktur.
Matt Quigley

"Kodladığımızda, test odaklı tasarım (TDD) kullanıyoruz. Bu, bazen özel ve test etmek isteyen bir işlevsellik parçasına rastladığımız anlamına gelir." Bu ifadeye kesinlikle katılmıyorum, daha fazla ayrıntı için lütfen aşağıdaki cevabıma bakın. TDD, özel yöntemleri test etmek zorunda olduğunuz anlamına gelmez. Özel yöntemleri test etmeyi seçebilirsiniz: ve bu sizin seçiminizdir, ancak böyle bir şey yapmanıza neden olan TDD değildir.
Matt Messersmith

41

Birkaç nedenden dolayı özel işlevselliği test etmekten hoşlanmıyorum. Bunlar aşağıdaki gibidir (bunlar TLDR çalışanlarının ana noktalarıdır):

  1. Genellikle bir sınıfın özel yöntemini test etmek istediğinizde, bu bir tasarım kokusudur.
  2. Bunları herkese açık arayüz üzerinden test edebilirsiniz (bu, onları nasıl test etmek istediğinizdir, çünkü müşteri bunları nasıl arayacak / kullanacaktır). Özel yöntemleriniz için tüm geçen testlerde yeşil ışığı görerek yanlış bir güvenlik hissi alabilirsiniz. Genel arayüzünüz aracılığıyla özel işlevlerinizdeki son durumları test etmek çok daha iyi / daha güvenlidir.
  3. Özel yöntemleri test ederek ciddi test yinelemeleri (çok benzeyen / çok benzeyen testler) riskiyle karşı karşıyasınız. Gereksinimler değiştiğinde bunun önemli sonuçları vardır, çünkü gereğinden fazla test kırılacaktır. Ayrıca, test takımınız nedeniyle yeniden düzenleme yapmanın zor olduğu bir konuma da getirebilir ... ki bu da en ironidir, çünkü test takımı güvenli bir şekilde yeniden tasarlamanıza ve yeniden yapılandırmanıza yardımcı olmak için oradadır!

Bunların her birini somut bir örnekle açıklayacağım. Görünüşe göre 2) ve 3) biraz karmaşık bir şekilde bağlı, bu yüzden örnekleri benzer, ancak onları özel yöntemleri test etmemeniz için ayrı nedenler olarak görüyorum.

Özel yöntemlerin test edilmesinin uygun olduğu zamanlar vardır, yukarıda listelenen olumsuzlukların farkında olmak sadece önemlidir. Daha sonra daha ayrıntılı olarak ele alacağım.

TDD'nin neden özel yöntemleri test etmek için geçerli bir bahane olmadığını da inceliyorum.

Kötü bir tasarımdan çıkış yolunuzu yeniden düzenleme

Gördüğüm en yaygın (anti) paternlardan biri Michael Feathers'ın "Buzdağı" sınıfı dediği şeydir ( Michael Feathers'ın kim olduğunu bilmiyorsanız, "Eski Kod ile Etkili Çalışma" kitabını satın alın / okuyun. profesyonel bir yazılım mühendisi / geliştiricisi olup olmadığınızı bilmeye değer bir kişi). Bu sorunun ortaya çıkmasına neden olan başka (anti) desenler de var, ancak bu karşılaştığım en yaygın model. "Buzdağı" sınıflarının tek bir genel yöntemi vardır ve geri kalanı özeldir (bu yüzden özel yöntemleri test etmek caziptir). Buna "Buzdağı" sınıfı denir, çünkü genellikle yalnız bir genel yöntem alay eder, ancak işlevselliğin geri kalanı su altında özel yöntemler şeklinde gizlenir.

Kural Değerlendiricisi

Örneğin, GetNextToken()dizeyi art arda çağırarak ve beklenen sonucu döndürdüğünü görerek test etmek isteyebilirsiniz . Bunun gibi bir işlev bir testi garanti eder: özellikle belirteç kurallarınız karmaşıksa bu davranış önemsiz değildir. Bu kadar karmaşık olmadığını farz edelim ve sadece boşlukla sınırlandırılmış jetonlara ip atmak istiyoruz. Yani bir test yazıyorsunuz, belki de böyle bir şeye benziyor (bazı dil agnostik psuedo kodu, umarım fikir açıktır):

TEST_THAT(RuleEvaluator, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    re = RuleEvaluator(input_string);

    ASSERT re.GetNextToken() IS "1";
    ASSERT re.GetNextToken() IS "2";
    ASSERT re.GetNextToken() IS "test";
    ASSERT re.GetNextToken() IS "bar";
    ASSERT re.HasMoreTokens() IS FALSE;
}

Aslında çok hoş görünüyor. Değişiklikler yaparken bu davranışı sürdürdüğümüzden emin olmak istiyoruz. Ama GetNextToken()bir olduğunu özel fonksiyon! Bu yüzden bu şekilde test edemeyiz, çünkü derlenmeyecek (Python gibi bazı komut dillerinin aksine, aslında kamu / özeli zorlayan bir dil kullandığımızı varsayarak). Peki ya RuleEvaluatorTek Sorumluluk İlkesini (Tek Sorumluluk İlkesini) izleyecek şekilde sınıfı değiştirmeye ne dersiniz ? Örneğin, bir ayrıştırıcı, belirteç ve değerlendiricinin bir sınıfa sıkışmış gibi görünüyor. Bu sorumlulukları ayırmak daha iyi olmaz mıydı? Üstelik, bir Tokenizersınıf oluşturursanız , o zaman herkese açık yöntemler HasMoreTokens()veGetNextTokens() . RuleEvaluatorSınıf olabilirdiTokenizerüye olarak nesne. Şimdi, yukarıdaki ile aynı testi koruyabiliriz, ancak Tokenizersınıfı test etmek yerineRuleEvaluator .

UML'de şöyle görünebilir:

Kural Değerlendiricisi Yeniden Düzenlendi

Bu yeni tasarımın modülerliği artırdığına dikkat edin, bu nedenle bu sınıfları sisteminizin diğer bölümlerinde tekrar kullanabilirsiniz (yapamadan özel yöntemler tanım gereği yeniden kullanılamaz). Bu, artan anlaşılabilirlik / konum ile birlikte RuleEvaluator'ı parçalamanın ana avantajıdır.

Test son derece benzer görünecektir, ancak GetNextToken()yöntem şimdi Tokenizersınıfta herkese açık olduğu için bu kez derlenecektir :

TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);

    ASSERT tokenizer.GetNextToken() IS "1";
    ASSERT tokenizer.GetNextToken() IS "2";
    ASSERT tokenizer.GetNextToken() IS "test";
    ASSERT tokenizer.GetNextToken() IS "bar";
    ASSERT tokenizer.HasMoreTokens() IS FALSE;
}

Herkese açık bir arayüz aracılığıyla özel bileşenleri test etme ve test tekrarından kaçınma

Sorununuzu daha az modüler bileşene ayırabileceğinizi düşünmeseniz bile ( bunu yapmaya çalışırsanız zamanın% 95'ini yapabilirsiniz), özel işlevleri genel bir arabirim aracılığıyla test edebilirsiniz. Çoğu zaman özel üyeler, genel arayüz aracılığıyla test edilecekleri için test edilmeye değmez. Gördüğüm çoğu zaman, çok görünen benzer , ancak iki farklı işlevi / yöntemi test eden testlerdir. Ne oluyor biter gereksinimleri değişiklik (ve her zaman yapmak) ne zaman, artık 1 yerine 2 kırık testleri Ve Gerçekten bütün özel yöntemler test varsa, daha fazla gibi 10 kırık testlerini yerine 1. olabileceğini olduğu kısacası , özel işlevleri test etme (FRIEND_TESTveya herkese açık hale getirme veya yansıma kullanma), aksi takdirde herkese açık bir arayüzle test edilebilen test yinelemesine neden olabilir ve / veya yansıma , genellikle uzun vadede pişman olursunuz.. Bunu gerçekten istemezsiniz, çünkü hiçbir şey sizi test takımınızdan yavaşlatmaz. Geliştirme süresini ve bakım maliyetlerini azaltması gerekiyor! Herkese açık bir arayüz aracılığıyla test edilen özel yöntemleri test ederseniz, test takımı tam tersini yapabilir ve bakım maliyetlerini aktif olarak artırabilir ve geliştirme süresini artırabilir. Özel bir işlevi herkese açık hale getirdiğinizde veyaFRIEND_TEST

TokenizerSınıfın aşağıdaki olası uygulamasını düşünün :

resim açıklamasını buraya girin

Diyelim ki SplitUpByDelimiter()dizideki her öğe bir belirteç olacak şekilde bir diziyi döndürmekten sorumludur. Dahası, GetNextToken()bunun sadece bu vektör üzerinde bir yineleyici olduğunu söyleyelim . Dolayısıyla, herkese açık testiniz şöyle görünebilir:

TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);

    ASSERT tokenizer.GetNextToken() IS "1";
    ASSERT tokenizer.GetNextToken() IS "2";
    ASSERT tokenizer.GetNextToken() IS "test";
    ASSERT tokenizer.GetNextToken() IS "bar";
    ASSERT tokenizer.HasMoreTokens() IS false;
}

Michael Feather'ın el yordamları aracı dediğimiz gibi davranalım . Bu, diğer kişilerin özel bölümlerine dokunmanıza izin veren bir araçtır. Bir örnek FRIEND_TESTgoogletest'ten veya dil destekliyorsa yansımadan kaynaklanır.

TEST_THAT(TokenizerTest, canGenerateSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);
    result_array = tokenizer.SplitUpByDelimiter(" ");

    ASSERT result.size() IS 4;
    ASSERT result[0] IS "1";
    ASSERT result[1] IS "2";
    ASSERT result[2] IS "test";
    ASSERT result[3] IS "bar";
}

Şimdi gereksinimlerin değiştiğini ve tokenleştirmenin çok daha karmaşık hale geldiğini varsayalım. Basit bir dize sınırlayıcının yeterli olmayacağına siz karar verirsiniz Delimiterve işi yapmak için bir sınıfa ihtiyacınız vardır . Doğal olarak, bir testin kırılmasını beklersiniz, ancak özel işlevleri test ettiğinizde bu ağrı artar.

Özel yöntemleri test etmek ne zaman uygun olabilir?

Yazılımda "tek beden herkese uyar" yoktur. Bazen "kuralları çiğnemek" iyidir (ve aslında idealdir). Mümkün olduğunda özel işlevselliği test etmemeyi şiddetle savunuyorum. İyi olduğunu düşündüğümde iki ana durum var:

  1. Eski sistemlerle yoğun bir şekilde çalıştım (bu yüzden bu kadar büyük bir Michael Feathers hayranıyım) ve bazen özel işlevselliği test etmenin bazen en güvenli olduğunu güvenle söyleyebilirim. Özellikle "karakterizasyon testlerini" taban çizgisine almak için faydalı olabilir.

  2. Aceleniz var ve şimdi ve burada mümkün olan en hızlı şeyi yapmak zorundasınız. Uzun vadede, özel yöntemleri test etmek istemezsiniz. Ancak, refactorun tasarım sorunlarını ele almasının genellikle biraz zaman alacağını söyleyeceğim. Ve bazen bir hafta içinde kargoya verilir. Sorun değil: hızlı ve kirli yapın ve işi yapmanın en hızlı ve en güvenilir yolu olduğunu düşünüyorsanız, bir groping aracı kullanarak özel yöntemleri test edin. Ancak, yaptığınız şeyin uzun vadede yetersiz olduğunu anlayın ve lütfen ona geri dönmeyi düşünün (veya unutulursa, ancak daha sonra görürseniz düzeltin).

Muhtemelen iyi olduğu başka durumlar da vardır. Bunun iyi olduğunu düşünüyorsanız ve iyi bir gerekçeniz varsa, o zaman yapın. Kimse seni durdurmuyor. Sadece potansiyel maliyetlerin farkında olun.

TDD Bahanesi

Bir kenara, TDD'yi özel yöntemleri test etmek için bir bahane olarak kullanan insanları gerçekten sevmiyorum. TDD uyguluyorum ve TDD'nin sizi bunu yapmaya zorladığını sanmıyorum. Önce testinizi (genel arayüzünüz için) yazabilir ve ardından bu arayüzü tatmin etmek için kod yazabilirsiniz. Bazen genel bir arayüz için bir test yazıyorum ve bir veya iki küçük özel yöntem de yazarak tatmin edeceğim (ancak özel yöntemleri doğrudan test etmiyorum, ancak çalıştıklarını veya genel testimin başarısız olacağını biliyorum. ). Bu özel yöntemin son durumlarını test etmem gerekirse, herkese açık arayüzümden onları vuracak bir sürü test yazacağım.Uç kasaları nasıl vuracağınızı anlayamıyorsanız, bu her biri kendi genel yöntemleriyle küçük bileşenlere yeniden bakmanız gereken güçlü bir işarettir. Bu, özel işlevlerin çok fazla yaptığınız ve sınıfın kapsamı dışında olduğunun bir işaretidir .

Ayrıca, bazen şu anda çiğnemek için çok büyük bir ısırık olan bir test yazıyorum ve bu yüzden "eh ile çalışmak için daha fazla API'm olduğunda daha sonra bu teste geri döneceğim" (Ben Bunu yorumlayacağım ve aklımın arkasında tutacağım). Bu noktada tanıştığım birçok geliştirici, TDD'yi günah keçisi olarak kullanarak özel işlevleri için testler yazmaya başlayacak. "Ah, başka bir teste ihtiyacım var, ama bu testi yazmak için bu özel yöntemlere ihtiyacım olacak. Bu nedenle, bir test yazmadan herhangi bir üretim kodu yazamadığım için, bir test yazmam gerekiyor özel bir yöntem için. " Ancak gerçekten yapmaları gereken şey, mevcut sınıflarına bir grup özel yöntem eklemek / test etmek yerine daha küçük ve yeniden kullanılabilir bileşenlere yeniden düzenleme yapmaktır.

Not:

Kısa bir süre önce GoogleTest kullanarak özel yöntemleri test etme hakkında benzer bir soruyu yanıtladım . Bu cevabı çoğunlukla burada daha fazla dil bilimi olmayacak şekilde değiştirdim.

PS İşte Michael Feathers'ın buzdağı sınıfları ve el yordamları araçları ile ilgili ders: https://www.youtube.com/watch?v=4cVZvoFGJTU


Çünkü ben bir avantaj olarak "potansiyel olarak sistemin diğer bölgelerinde bu sınıfları yeniden kullanabilirsiniz" listeleme ile olan sorun, bazen bir işlev özeldir işaretlemek nedeni olmasıdır yok o diğer bölgelerinde kullandığı istiyorum sistemi. Bu dile özgü bir sorundur: ideal olarak, bu bir "modül" için özel olurdu, ancak dil bunu desteklemiyorsa (örneğin PHP), sınıfım birimi değil modülü temsil eder: özel yöntemler yeniden kullanılabilir koddur kendi sözleşmeleriyle, ancak yalnızca bu sınıf içinde yeniden kullanılması gerekir.
IMSoP

Ne dediğini anlıyorum, ama Python topluluğunun bu sorunu ele alma şeklini seviyorum. Söz konusu "özel" üyeyi bir liderle adlandırırsanız _, "hey, bu " özel " sinyalini verir. Bunu kullanabilirsiniz, ancak tam açıklama, yeniden kullanım için tasarlanmamıştır ve yalnızca gerçekten ne yaptığını biliyorum ". Herhangi bir dilde aynı yaklaşımı uygulayabilirsiniz: bu üyeleri herkese açık hale getirin, ancak bir liderle işaretleyin _. Ya da belki de bu fonksiyonlar gerçekten özel olmalı ve sadece genel bir arayüz üzerinden test edilmelidir (daha fazla bilgi için cevaba bakınız). Her durumda, genel bir kural yok
Matt Messersmith

26

Bence bir nesnenin genel arayüzünü test etmek en iyisidir. Dış dünyanın bakış açısından, sadece kamusal arayüzün davranışı önemlidir ve bu, birim testlerinizin yönlendirilmesi gereken şeydir.

Bir nesne için bazı katı birim testleri yazıldıktan sonra, arayüzün arkasındaki uygulama değiştiği için geri dönmek ve bu testleri değiştirmek istemezsiniz. Bu durumda, birim testinizin tutarlılığını bozdunuz.


21

Özel yönteminiz genel yöntemlerinizi çağırarak test edilmezse ne yapıyor? Korunmasız veya arkadaşım olmayan özel konuşuyorum.


3
Teşekkür ederim. Bu şaşırtıcı derecede az yorumlanmış ve özellikle yazılmasından bu yana neredeyse 8 yıl sonra bile hala geçerli.
Sauronlord

1
Aynı akıl yürütme ile sadece yazılım kullanıcı arayüzünden test edilebilir (sistem seviyesi testi), çünkü yazılımdaki her fonksiyon bir şekilde oradan yürütülecektir.
Dirk Herrmann

18

Özel yöntem iyi tanımlanmışsa (yani, test edilebilir ve zaman içinde değişmesi amaçlanmamış bir işlevi varsa) evet. Test edilebilir her şeyi mantıklı bir yerde test ediyorum.

Örneğin, bir şifreleme kitaplığı, bir seferde yalnızca 8 bayt şifreleyen özel bir yöntemle blok şifreleme gerçekleştirdiği gerçeğini gizleyebilir. Bunun için bir birim testi yazardım - gizli olsa bile değişmesi gerekiyordu ve eğer kırılırsa (örneğin gelecekteki performans geliştirmeleri nedeniyle), o zaman sadece kırılmayan özel işlev olduğunu bilmek istiyorum kamu görevlerinden birinin kırılması.

Daha sonra hata ayıklamayı hızlandırır.

-Adam


1
Bu durumda, bu özel yöntemi başka bir sınıfa taşımak, daha sonra onu genel veya genel statik yapmak mantıklı değil miydi?
Yasadışı Programcı

+1 Özel üye işlevlerinizi test etmezseniz ve genel arabirim testiniz başarısız olursa, alacağınız tek şey, bir şeyin ne olduğu hakkında hiçbir fikre sahip olmadan bir şeyin kırıldığı bir sonuçtur .
Olumide

12

Test odaklı (TDD) geliştiriyorsanız, özel yöntemlerinizi test edersiniz.



4
Doğru değil, genel yöntemlerinizi test edin ve testler geçtikten sonra, genel yöntemlerinizdeki kodu "temizleme" adımına dayanan özel yöntemlere çıkarırsınız. Özel yöntemleri test etmek kötü bir fikir imo çünkü uygulama şeklini değiştirmeyi zorlaştırıyor (bir gün bir şeyi nasıl yaptığınızı değiştirmek isterseniz, bunu değiştirebilmeniz ve tüm testlerinizi çalıştırabilmeniz ve yeni yapma yönteminiz bir şey geçmeleri doğru, bunun için tüm özel testlerimi değiştirmek istemem).
Tesseract

1
@Tegeract, yorumunuzu bir kereden fazla oylayabilirsem. “... bunu değiştirebilmeli ve tüm testlerini yapmalısın ve yeni bir şey yapmanın doğru yolu geçerse geçmeli” BU, birim testlerin en önemli avantajlarından biri. Güvenle refactor yapmanızı sağlar. Sınıfınızın iç özel çalışmalarını tamamen değiştirebilirsiniz ve (tüm birim testlerinizi yeniden yazmadan), tüm (mevcut) birim testleriniz (genel arayüzünüzde) hala geçtiği için hiçbir şeyi kırmadığınızdan emin olabilirsiniz.
Lee

Katılmıyorum, aşağıdaki cevabımı gör
Matt Messersmith

11

Bu alanda uzman değilim, ancak birim testi, davranışı test etmeli, uygulamayı değil. Özel yöntemler kesinlikle uygulamanın bir parçasıdır, bu nedenle IMHO test edilmemelidir.


Uygulama nerede test edilir? Bazı işlevler önbelleğe alma kullanıyorsa, bu bir uygulama ayrıntısıdır ve önbellekleme test edilmez mi?
Dirk Herrmann

11

Özel yöntemleri çıkarım yoluyla test ediyoruz, yani toplam sınıf testi kapsamını en az% 95 oranında aradık, ancak sadece testlerimiz genel veya dahili yöntemlere çağrı yapıyoruz. Kapsamı elde etmek için, meydana gelebilecek farklı senaryolara dayanarak kamuya / kurumlara birden fazla çağrı yapmamız gerekir. Bu, testlerimizi test ettikleri kodun amacı etrafında daha kasıtlı hale getirir.

Trumpi'nin bağladığınız gönderinin cevabı en iyisidir.


9

Ünite testleri, genel yöntemleri test etmek için olduğuna inanıyorum. Herkese açık yöntemleriniz özel yöntemlerinizi kullanır, dolaylı olarak da test edilirler.


7

Bir süredir özellikle TDD'de elimi denerken bu konuyu araştırıyorum.

TDD davasında bu soruna yeterince değindiğini düşündüğüm iki gönderiyle karşılaştım.

  1. Özel yöntemlerin test edilmesi, TDD ve Test Odaklı Yeniden Düzenleme
  2. Test Odaklı Geliştirme Test Etmiyor

Özetle:

  • Test güdümlü geliştirme (tasarım) tekniklerini kullanırken, özel yöntemler yalnızca halihazırda çalışan ve test edilmiş kodun yeniden faktoring işlemi sırasında ortaya çıkmalıdır.

  • Sürecin doğası gereği, tamamen test edilmiş bir fonksiyondan çıkarılan herhangi bir basit uygulama işlevselliği, kendi kendini test edecektir (yani dolaylı test kapsamı).

Bana göre kodlamanın başlangıcında çoğu yöntemin daha üst düzey fonksiyonlar olacağı açıktır, çünkü tasarım kapsüllenir / tanımlanır.

Bu nedenle, bu yöntemler halka açık olacak ve bunları test etmek yeterince kolay olacaktır.

Her şey yolunda gittiğinde özel yöntemler daha sonra gelecek ve okunabilirlik ve temizlik uğruna çarpanlara ayırıyoruz .


6

Yukarıda belirtildiği gibi, "Özel yöntemlerinizi test etmiyorsanız, kırılmayacaklarını nasıl biliyorsunuz?"

Bu önemli bir konudur. Birim testlerin en önemli noktalarından biri, bir şeyin ASAP'ı nerede, ne zaman ve nasıl kırdığını bilmek. Böylece önemli miktarda gelişme ve KG çabası azalır. Test edilen her şey halka açıksa, o zaman sınıfın içlerini dürüst bir şekilde kapsamaz ve tasvir etmezsiniz.

Bunu yapmanın en iyi yollarından birini buldum, sadece projeye test referansını eklemek ve testleri özel yöntemlere paralel bir sınıfa koymak. Testlerin nihai projeye dahil edilmemesi için uygun yapı mantığını koyun.

Daha sonra bu yöntemleri test etmenin tüm avantajlarına sahipsiniz ve sorunları dakikalar veya saatler arasında bulabilirsiniz.

Özetle, evet, birim özel yöntemlerinizi test edin.


2
Katılmıyorum. "Özel yöntemlerinizi test etmezseniz, onların kırılmayacaklarını nasıl anlarsınız?" : Bunu biliyorum, çünkü özel yöntemlerim bozulursa, o zaman bu özel yöntemlere dayanan genel yöntemlerimi test eden testler başarısız olur. Genel yöntemlerin nasıl uygulanacağı konusundaki fikrimi her değiştirdiğimde testlerimi değiştirmek istemiyorum. Ayrıca, birim testlerin ana ilgisinin hangi kod satırının hatalı olduğunu bilmek olmadığını, bunun yerine değişiklik yaparken (özel yöntemlerde) herhangi bir şey kırmamanız konusunda az ya da çok emin olmanızı sağlar.
Tesseract

6

Yapmamalısın . Özel yöntemleriniz test edilmesi gereken yeterli karmaşıklığa sahipse, bunları başka bir sınıfa koymalısınız. Keep yüksek uyumu , bir sınıf tek bir amacı olmalıdır. Sınıf genel arayüzü yeterli olmalıdır.


3

Özel yöntemlerinizi test etmezseniz, bunların kırılmayacağını nasıl anlarsınız?


19
Herkese açık yöntemlerinizin testlerini yazarak.
scubabbl

3
Bu özel yöntemler sözde sınıfın genel yöntemleri tarafından çağrılır. Bu nedenle, özel yöntemleri çağıran genel yöntemleri test edin.
jop

1
Genel yöntemleriniz düzgün çalışıyorsa, eriştikleri özel yöntemler düzgün bir şekilde çalışıyor demektir.
17 of 26

Genel yöntemlerinizin testleri başarısız olursa, nesnenizin / bileşeninizin / vb. Bir şeyin daha düşük bir düzeyde doğru olmadığını hemen anlarsınız.
Rob

3
Bu var gerçekten o (iç fonksiyonları gayet ve dış odaklanmak olduğunu veya tam tersi) kırdı sadece dış fonksiyonlarını bir iç fonksiyon olduğu ve olmadığı bilmek, ancak, güzel.
Adam Davis

2

Belli ki dile bağlı. Geçmişte c ++ ile, test sınıfını bir arkadaş sınıfı olarak ilan ettim. Ne yazık ki, bu, üretim kodunuzun test sınıfı hakkında bilgi sahibi olmasını gerektirir.


5
Arkadaş anahtar kelimesi beni üzüyor.
Rob

Test sınıfı başka bir projede uygulanırsa bu sorun olmaz. Önemli olan, üretim kodunun test sınıfına başvurmamasıdır.
Olumide

2

Özel yöntemlerin uygulama ayrıntıları olarak değerlendirildiği ve daha sonra test edilmesi gerekmediği bakış açısını anlıyorum. Ve eğer sadece nesnenin dışında gelişmek zorunda olsaydık bu kurala bağlı kalırdım. Ama biz, sadece nesnelerin dışında gelişen ve sadece kamusal yöntemlerini çağıran bir tür kısıtlı geliştiriciler miyiz? Yoksa aslında bu nesneyi mi geliştiriyoruz? Nesnelerin dışında programlamak zorunda olmadığımızdan, muhtemelen bu özel yöntemleri geliştirdiğimiz yeni kamusal yöntemlere çağırmamız gerekecek. Özel yöntemin tüm oranlara karşı olduğunu bilmek harika olmaz mıydı?

Bazı insanlar bu nesneye başka bir kamu yöntemi geliştirirsek, o zaman bu test edilmelidir ve bu (özel yöntem test olmadan yaşamaya devam edebilir) cevap verebilir biliyorum. Ancak bu, bir nesnenin genel yöntemleri için de geçerlidir: bir web uygulaması geliştirilirken, bir nesnenin tüm genel yöntemleri denetleyici yöntemlerinden çağrılır ve dolayısıyla denetleyiciler için uygulama ayrıntıları olarak düşünülebilir.

Öyleyse neden nesneleri test ediyoruz? Çünkü kontrolörlerin yöntemlerini, temel kodun tüm dallarını tetikleyecek uygun girdiyle test ettiğimizden emin olmak imkansız demek zor. Başka bir deyişle, yığın içinde ne kadar yüksek olursak, tüm davranışı test etmek o kadar zor olur. Özel yöntemler için de aynı şey geçerlidir.

Benim için özel ve kamusal yöntemler arasındaki sınır, testler söz konusu olduğunda psikolojik bir ölçüttür. Benim için daha önemli olan kriterler:

  • yöntem farklı yerlerden birden fazla mı çağrılıyor?
  • yöntem test gerektirecek kadar sofistike mi?

1

Özel yöntemin kendi testlerini gerektirecek kadar büyük veya karmaşık veya önemli olduğunu fark edersem, onu başka bir sınıfa koyup orada herkese açık hale getiriyorum (Yöntem Nesnesi). O zaman kendi sınıfında yaşayan daha önce özel ama şimdi herkese açık yöntemi kolayca test edebilirim.


1

Birim Testi kavramını asla anlamadım ama şimdi amacının ne olduğunu biliyorum.

Birim Testi tam bir test değildir . Bu nedenle, KG ve manuel testin yerini tutmaz. TDD kavramı bu açıdan yanlıştır, çünkü özel yöntemler de dahil olmak üzere her şeyi test edemezsiniz, aynı zamanda kaynakları kullanan yöntemler de (özellikle kontrolümüz olmayan kaynaklar). TDD tüm kalitesine dayanarak elde edilemediği bir şeydir.

Birim testi daha çok pivot testidir Bazı pivotları işaretlersiniz ve pivot sonucu aynı kalmalıdır.


1

Herkese açık ve özel arasında, apilerin testlerinizden ne çağıracakları için yararlı bir ayrım veya yöntemle sınıf arasında bir ayrım yoktur. Test edilebilir birimlerin çoğu bir bağlamda görülebilir ancak diğerlerinde gizlidir.

Önemli olan kapsam ve maliyetlerdir. Projenizin kapsama hedeflerine ulaşırken maliyetleri en aza indirmeniz gerekir (hat, şube, yol, blok, yöntem, sınıf, denklik sınıfı, kullanım örneği ... takımın kararı ne olursa olsun).

Bu yüzden kapsamı sağlamak için araçlar kullanın ve testlerinizi en az maliyete (kısa ve uzun vadeli ) neden olacak şekilde tasarlayın .

Testleri gerekenden daha pahalı yapmayın. Sadece halka açık giriş noktalarını test etmek en ucuz ise bunu yapın. Özel yöntemleri test etmek en ucuzuysa, bunu yapın.

Daha deneyimli hale geldikçe, test bakımının uzun vadeli maliyetlerinden kaçınmak için ne zaman yeniden düzenlemeye değer olduğunu tahmin etme konusunda daha iyi olacaksınız.


0

Eğer yöntem yeterince önemli / karmaşıksa, genellikle "korumalı" yapacağım ve test edeceğim. Bazı yöntemler özel bırakılacak ve genel / korunan yöntemler için birim testlerin bir parçası olarak örtük olarak test edilecektir.


1
@VisibleForTesting bunun için bir ek açıklamadır. Ben test için kapsülleme rahatlamak değil, yerine dp4j.com kullanın
simpatico

0

Birçok insanın aynı düşünce tarzında olduğunu görüyorum: kamu düzeyinde test. ama KG ekibimizin yaptığı şey bu değil mi? Girdi ve beklenen çıktıları test ederler. Eğer geliştiriciler olarak sadece genel yöntemleri test edersek, sadece KG'nin işini tekrar yapıyoruz ve "birim testi" ile herhangi bir değer katmıyoruz.


Mevcut eğilim azaltmak veya hiç KG ekibine sahip olmamaktır. Bu birim testleri, bir mühendis ana kola kod her bastığında otomatik testler haline gelir. KG ile bile, tüm uygulamayı otomatik testler kadar hızlı test edebilmeleri mümkün değildir.
Patrick Desjardins

0

"Özel yöntemleri test etmeli miyim?" Bazen". Tipik olarak sınıflarınızın arayüzüne karşı test yapmalısınız.

  • Bunun nedenlerinden biri, bir özellik için iki kez kapsama gerek duymamanızdır.
  • Başka bir neden, özel yöntemleri değiştirirseniz, nesnenizin arayüzü hiç değişmemiş olsa bile, onlar için her testi güncellemeniz gerekecektir.

İşte bir örnek:

class Thing
  def some_string
    one + two
  end

  private 

  def one
    'aaaa'
  end

  def two
    'bbbb'
  end

end


class RefactoredThing
def some_string
    one + one_a + two + two_b
  end

  private 

  def one
    'aa'
  end

  def one_a
    'aa'
  end

  def two
    'bb'
  end

  def two_b
    'bb'
  end
end

In RefactoredThingsize şimdi üstlenmeden için güncellemek zorunda 2 olmak üzere 5 testler, var ama senin nesnenin işlevselliği gerçekten değişmemiştir. Diyelim ki işler bundan daha karmaşık ve çıktının sırasını tanımlayan bazı yöntemleriniz var:

def some_string_positioner
  if some case
  elsif other case
  elsif other case
  elsif other case
  else one more case
  end
end

Bu bir dış kullanıcı tarafından çalıştırılmamalıdır, ancak kapsülleme sınıfınız bu mantığı tekrar tekrar çalıştırmak için çok ağır olabilir. Bu durumda belki de bunu ayrı bir sınıfa çıkarmayı, o sınıfa bir arayüz vermeyi ve buna karşı test etmeyi tercih edersiniz.

Ve son olarak, ana nesnenizin süper ağır olduğunu ve yöntemin oldukça küçük olduğunu ve çıktının doğru olduğundan emin olmanız gerektiğini varsayalım. "Bu özel yöntemi denemek zorundayım!" Diye düşünüyorsunuz. Başlangıç ​​işinin bir parametresini başlangıç ​​parametresi olarak geçirerek belki nesnenizi daha hafif hale getirebilirsiniz mi? Sonra daha hafif bir şey geçirebilir ve buna karşı test edebilirsiniz.


0

Hayır Özel Yöntemleri neden test etmemelisiniz ? ve ayrıca Mockito gibi popüler alaycı çerçeve, özel yöntemleri test etmek için destek sağlamaz.


0

Ana noktalardan biri

Eğer mantığın doğruluğunu test edersek ve özel bir yöntem bir mantık taşıyorsa, onu test etmeliyiz. Öyle değil mi? Öyleyse neden atlayacağız?

Yöntemlerin görünürlüğüne dayalı testler yazmak tamamen alakasız bir fikirdir.

tersine

Öte yandan, orijinal sınıfın dışında özel bir yöntem çağırmak ana sorundur. Ve ayrıca bazı alay araçlarında özel bir yöntemle alay etmek için sınırlamalar vardır. (Örn: Mockito )

Power Mock gibi bunu destekleyen bazı araçlar olmasına rağmen , bu tehlikeli bir işlemdir. Bunun nedeni, bunu başarmak için JVM'yi hacklemesidir.

Etrafında yapılabilecek bir çalışma (Özel yöntemler için test senaryoları yazmak istiyorsanız)

Bu özel yöntemleri şu şekilde beyan edin: korumalı bildirin . Ancak birkaç durum için uygun olmayabilir.


0

Bu sadece genel veya özel yöntemler veya işlevlerle değil, uygulama ayrıntılarıyla da ilgilidir. Özel işlevler, uygulama ayrıntılarının yalnızca bir yönüdür.

Sonuçta, birim testi beyaz kutu test yaklaşımıdır. Örneğin, kodun şu ana kadar test sırasında ihmal edilen bölümlerini tanımlamak için kapsama analizini kullanan kişi uygulama ayrıntılarına girer.

C) Evet, uygulama ayrıntılarını test ediyor olmalısınız:

Performans nedenleriyle 10'a kadar öğe varsa özel bir BubbleSort uygulamasını ve 10'dan fazla öğe varsa farklı bir sıralama yaklaşımının (örneğin, yığın) özel bir uygulamasını kullanan bir sıralama işlevi düşünün. Genel API bir sıralama işlevidir. Ancak test takımınız, aslında kullanılan iki tür algoritmanın olduğu bilgisini daha iyi kullanır.

Bu örnekte, elbette, herkese açık API üzerinde testler yapabilirsiniz. Bununla birlikte, bu, heapsort algoritması yeterince iyi test edilecek şekilde sıralama işlevini 10'dan fazla öğeyle yürüten bir dizi test vakasına sahip olmayı gerektirir. Bu tür test durumlarının tek başına varlığı, test takımının işlevin uygulama ayrıntılarına bağlı olduğunun bir göstergesidir.

Sıralama işlevinin uygulama ayrıntıları değişirse, belki de iki sıralama algoritması arasındaki sınırın kaydırılması veya yığın kümesinin birleştirme veya başka bir yöntemle değiştirilmesi şeklinde: Var olan testler çalışmaya devam eder. Yine de değerleri sorgulanabilir ve değiştirilmiş sıralama işlevini daha iyi test etmek için muhtemelen yeniden işlenmeleri gerekir. Başka bir deyişle, testlerin herkese açık API'da olmasına rağmen bir bakım çabası olacaktır.

B) Uygulama detayları nasıl test edilir?

Birçok kişinin özel işlevleri veya uygulama ayrıntılarını test etmemesi gerektiğini iddia etmesinin bir nedeni, uygulama ayrıntılarının değişme olasılığının yüksek olmasıdır. Bu yüksek değişim olasılığı en azından arayüzlerin arkasındaki uygulama ayrıntılarını gizlemenin nedenlerinden biridir.

Şimdi, arayüzün arkasındaki uygulamanın, dahili arayüz üzerindeki bireysel testlerin bir seçenek olabileceği daha büyük özel parçalar içerdiğini varsayalım. Bazı insanlar, bu bölümlerin özel olduğunda test edilmemesi gerektiğini, kamuya açık bir şeye dönüştürülmesi gerektiğini savunuyor. Herkese açık olduğunda, bu kodun birim testi iyi olur.

Bu ilginç: Arayüz dahili iken, bir uygulama detayı olarak değişmesi muhtemeldi. Aynı arabirimi kullanmak, onu herkese açık hale getirmek, sihirli bir dönüşüm yapar, yani değişmesi daha az olası bir arabirime dönüştürür. Açıkçası bu tartışmada bazı kusurlar var.

Bununla birlikte, bunun arkasında bazı gerçekler vardır: Uygulama ayrıntılarını test ederken, özellikle dahili arayüzleri kullanarak, kararlı olması muhtemel arayüzleri kullanmaya çalışılmalıdır. Bununla birlikte, bazı arayüzlerin kararlı olup olmayacağı, genel veya özel olmasına bağlı olarak sadece karar verilemez. Bir süredir üzerinde çalıştığım projelerde, kamusal arayüzler de genellikle yeterince değişti ve birçok özel arayüz, uzun zamandır dokunulmadan kaldı.

Yine de "önce ön kapı" yı kullanmak iyi bir kuraldır (bkz. Http://xunitpatterns.com/Principles%20of%20Test%20Automation.html ). Ancak, "yalnızca ön kapı" değil "ilk kapı" olarak adlandırıldığını unutmayın.

C) Özet

Uygulama ayrıntılarını da test edin. Kararlı arayüzlerde (genel veya özel) test yapmayı tercih edin. Uygulama ayrıntıları değişirse, genel API ile ilgili testlerin de gözden geçirilmesi gerekir. Özel bir şeyi halka dönüştürmek kararlılığını sihirli bir şekilde değiştirmez.


0

Evet, mümkün olan yerlerde özel yöntemleri test etmelisiniz. Neden? Sonuçta aynı özel işlevlerin aynı girdiler üzerinde tekrar tekrar örtülü olarak test edilmesine neden olan test durumlarının gereksiz durum uzay patlamasından kaçınmak için . Neden bir örnekle açıklayalım.

Aşağıdaki biraz uyuşuk örneği düşünün. Diyelim ki 3 tamsayı alan ve yalnızca bu 3 tamsayının hepsi asalsa, true döndüren bir işlevi herkese açık olarak göstermek istiyoruz. Bunu şu şekilde uygulayabiliriz:

public bool allPrime(int a, int b, int c)
{
  return andAll(isPrime(a), isPrime(b), isPrime(c))
}

private bool andAll(bool... boolArray)
{
  foreach (bool b in boolArray)
  {
    if(b == false) return false;
  }
  return true;
}

private bool isPrime(int x){
  //Implementation to go here. Sorry if you were expecting a prime sieve.
}

Şimdi, sadece kamu fonksiyonlarının test edilmesi gerektiği konusunda katı bir yaklaşım benimseseydik, sadece test etmemize izin verilirdi, ya da allPrimedeğil .isPrimeandAll

Bir test kullanıcısı olarak, her görüşün beş olasılıklar ilginizi çekebilir: < 0, = 0, = 1, prime > 1, not prime > 1. Ancak ayrıntılı olmak gerekirse, argümanların her kombinasyonunun nasıl birlikte oynadığını da görmeliyiz. Yani bu 5*5*5= 125 test vakası Sezgilerimize göre bu işlevi iyice test etmemiz gerekir.

Öte yandan, özel fonksiyonları test etmemize izin verilirse, daha az test vakası ile çok fazla zemin kaplayabiliriz. isPrimeÖnceki sezgimizle aynı seviyeyi test etmek için sadece 5 test vakasına ihtiyacımız var . Ve Daniel Jackson tarafından önerilen küçük kapsam hipotezi ile , andAllfonksiyonu sadece 3 veya 4 gibi küçük bir uzunluğa kadar test etmemiz gerekir . Bu, en fazla 16 test daha olurdu. Yani toplam 21 test. Tabii ki, muhtemelen birkaç test yapmak istiyoruz allPrime, ancak önemsediğimizi söylediğimiz 125 giriş senaryosunun tamamını kapsamlı bir şekilde kapsamak zorunda hissetmeyiz. Sadece birkaç mutlu yol.

Kesin bir örnek, ama açık bir gösteri için gerekliydi. Ve desen gerçek yazılıma uzanır. Özel fonksiyonlar genellikle en düşük seviyedeki yapı taşlarıdır ve bu nedenle daha yüksek seviyeli mantık elde etmek için genellikle bir araya getirilirler. Daha yüksek seviyelerde, çeşitli kombinasyonlar nedeniyle daha düşük seviyeli şeylerin daha fazla tekrarına sahibiz.


İlk olarak, gösterdiğiniz gibi saf işlevlerle böyle kombinasyonları test etmek zorunda değilsiniz. Çağrılar isPrimegerçekten bağımsızdır, bu nedenle her kombinasyonu körü körüne test etmek oldukça maksatsızdır. İkincisi, isPrimeözel adı verilen saf bir işlevi işaretlemek o kadar çok tasarım kuralını ihlal ediyor ki nereden başlayacağımı bile bilmiyorum. isPrimeçok açık bir şekilde kamusal bir işlev olmalıdır. Bu son derece zayıf örneğe bakılmaksızın söylediklerinizi elde ediyorum. Ancak , gerçek yazılım sistemlerinde bu nadiren iyi bir fikir olduğunda, kombinasyon testi yapmak istediğiniz öncül üzerine inşa edilmiştir .
Matt Messersmith

Matt evet örnek size vermeyeceğim ideal değil. Ancak ilke açık olmalıdır.
Colm Bhandal

Öncül, tam olarak kombinasyon testi yapmak istemezsiniz. Kendinizi bulmacanın sadece herkese açık parçalarını test etmekle kısıtladıysanız, yapmanız gerekir. Uygun kapsülleme ilkelerine uymak için saf bir işlevi özel yapmak istediğiniz durumlar vardır. Ve bu saf özel işlev halka açık olanlar tarafından kullanılabilir. Kombine bir şekilde, belki de diğer saf özel işlevlerle. Bu durumda, özel olarak test etmeyeceğiniz dogmayı izleyerek, özel bileşenlerin modüler testini yapmak yerine, ortak işlev üzerinde kombinasyon testi yapmak zorunda kalırsınız.
Colm Bhandal

0

Yöntem paketinizi özel olarak da varsayılan hale getirebilirsiniz ve özel olması gerekmedikçe birim testini yapabilmeniz gerekir.

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.