Birim testi özel yöntemleri neden kötü uygulama olarak değerlendiriliyor?


18

Bağlam:

Şu anda Python'da küçük bir proje üzerinde çalışıyorum. Ben sık belgelenmiştir bazı kamu yöntemlerle derslerimi yapısı ama esas üst düzey kavramları (sınıfın bir kullanıcı tanımak ve kullanmak gerektiğini) ve bir grup ile anlaşma gizli sorumlu olan yöntemler (alt çizgi ile başlayan) karmaşık veya düşük seviyeli işleme.

Kodlara güven vermek ve daha sonra yapılacak herhangi bir değişikliğin önceki davranışı bozmadığından emin olmak için testlerin gerekli olduğunu biliyorum.

Sorun:

Üst düzey genel yöntemleri güvenilir bir temelde oluşturmak için genellikle özel yöntemleri test ederim. Bir kod değişikliği regresyonlar ve nerede tanıttı olup olmadığını bulmak daha kolay buluyorum. Bu, dahili testlerin küçük revizyonları ihlal edebileceği ve düzeltilmesi / değiştirilmesi gerektiği anlamına gelir

Ancak, birim test özel yönteminin en azından tartışmalı bir kavram olduğunu veya daha sıklıkla kötü uygulama olarak kabul edildiğini de biliyorum. Nedeni: sadece kamu davranışları test edilmelidir ( ref. )

Soru:

En iyi uygulamaları takip etmeye önem veriyorum ve anlamak istiyorum:

  • Özel / gizli yöntemlerde birim testleri kullanmak neden kötüdür (risk nedir)?
  • genel yöntemler düşük seviye ve / veya karmaşık işlemeyi kullanabiliyorsa en iyi uygulamalar nelerdir?

Precisions:

  • bu nasıl sorgulanacağı değil. Python'un gerçek gizlilik kavramı yoktur ve gizli yöntemler basit bir şekilde listelenmez, ancak adlarını bildiğinizde kullanılabilir
  • Bana hiç programlama kuralları ve kalıpları öğretilmiyordu: son derslerim 80'li yıllardan ... Temelde deneme-yanılma ve internette referanslarla dil öğrendim (Stack Exchange yıllardır benim favorim)


2
OP, özel yöntemlerin testinin "kötü" olduğunu düşündüğünüzü nereden duydunuz veya okudunuz? Birim testi yapmanın farklı yolları vardır. Bkz. Birim testi, Kara kutu testi ve Beyaz kutu testi .
John Wu

@JohnWu: Beyaz kutu ve Kara kutu testi arasındaki farkı biliyorum. Ancak Beyaz kutu testinde bile, özel yöntemleri test etme ihtiyacı bir tasarım problemi için bir ipucu gibi görünüyor. Benim sorum, oraya düştüğümde en iyi yolların ne olduğunu anlamaya çalışmak ...
Serge Ballesta

2
Yine, White-box testinde bile özel yöntemleri test etme ihtiyacının bir tasarım problemi için bir ipucu olduğunu duydunuz veya okudunuz mu? Bir cevap girişiminde bulunmadan önce bu inancın ardındaki mantığı anlamak istiyorum.
John Wu

Diğer bir deyişle, özel yöntemleri test etmenin kötü bir uygulama olduğuna inanmanızı sağlayan makalelere bazı referanslar koyun. O zaman bize neden onlara inandığını açıkla.
Laiv

Yanıtlar:


18

Birkaç neden:

  1. Tipik olarak bir sınıfın özel yöntemini test etmek istediğinizde bu bir tasarım kokusudur (buzdağı sınıfı, yeterli yeniden kullanılabilir genel bileşenler vb.). Oyunda neredeyse her zaman bazı "daha büyük" sorunlar var.

  2. Bunları genel arayüz aracılığıyla test edebilirsiniz (bu, onları nasıl test etmek istediğinizdir, çünkü istemci 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 çoğaltması (çok benzeyen / çok benzeyen testler) riskiyle karşı karşıya kalırsı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 süitiniz nedeniyle yeniden düzenleme yapmanın zor olduğu bir konuma da getirebilir ... ki bu da en ironidir, çünkü test paketi güvenli bir şekilde yeniden tasarlamanıza ve refactor'a yardımcı olmak için oradadır!

Özel parçaları test etmek için hala cazipseniz bir ipucu (sizi ve YMMV'yi rahatsız ediyorsa kullanmayın, ancak geçmişte benim için iyi çalıştı): Bazen emin olmak için özel işlevler için birim testleri yazmak tam olarak nasıl değerli olabileceğini düşündüğünüz şekilde çalışıyorlar (özellikle bir dilde yeni iseniz). Ancak, çalıştıklarından emin olduktan sonra, testleri silin ve herkesin söz konusu özel işlevde korkunç bir değişiklik yapması durumunda herkesin karşılaştığı testlerin sağlam olduğundan ve her zaman yakalanacağından emin olun .

Özel yöntemler ne zaman test edilir: Bu cevap (bir şekilde) popüler hale geldiğinden, "en iyi uygulama" nın her zaman sadece "en iyi uygulama" olduğunu belirtmek zorunda hissediyorum. Bu dogmatik veya körü körüne yapmanız gerektiği anlamına gelmez. Özel yöntemlerinizi test etmeniz ve meşru bir nedeniniz olduğunu düşünüyorsanız (eski bir uygulama için karakterizasyon testleri yazarken olduğu gibi), özel yöntemlerinizi test edin . Özel durumlar her zaman herhangi bir genel kuralı veya en iyi uygulamayı gölgede bırakır. Sadece yanlış gidebilecek bazı şeylerin farkında olun (yukarıya bakın).

Burada tekrar etmeyeceğim SO üzerinde bu ayrıntılı olarak cevap bir cevap var: /programming/105007/should-i-test-private-methods-or-only-public-ones/ 47401015 # 47401015


4
Sebep 1: Bulutsu. Sebep 2: Özel yardımcı yönteminiz herkese açık API'nın bir parçası değilse ne olur? Sebep 3: Sınıfınızı doğru tasarlarsanız değil. Son ipucunuz: Yazdığım bir yöntemin işe yaradığını kanıtlayan mükemmel bir testi neden silmeliyim?
Robert Harvey

4
@RobertHarvey Sebep 2: genel API aracılığıyla dolaylı olarak erişilebilir olma! = Genel API'nın bir parçası olma. Özel işleviniz genel API aracılığıyla test edilemiyorsa, belki de ölü bir koddur ve kaldırılmalıdır? Ya da sınıfınız gerçekten bir buzdağıdır (neden 1) ve yeniden düzenlenmesi gerekir.
Frax

5
@RobertHarvey, ortak bir API aracılığıyla özel bir işlevi test edemiyorsanız, yararlı bir amaca hizmet etmediği için silin.
David Arno

1
@RobertHarvey 1: Tasarım kokuları her zaman biraz öznel / belirsiz, çok emin. Ama bazı anti-desen örnekleri listeledim ve SO cevabımda daha fazla ayrıntı var. 2: Özel yöntemler genel API'nin bir parçası olamaz (tanım gereği: özeldir) ... bu yüzden sorunuzun çok anlamlı olduğunu düşünmüyorum. Ben bin_search(arr, item)(kamu) ve bin_search(arr, item, low, hi)(özel, bin arama yapmak için birçok yolu vardır ) bir şey varsa , o zaman test etmek için gereken tek kamu ( bin_search(arr, item))
Matt Messersmith

1
@RobertHarvey 3: Öncelikle risk dedim , garanti değil . İkincisi, "düzgün yaparsanız işe yarıyor" iddiası kendi kendini gerçekleştirir. Örneğin, " Düzgün yaparsanız bir işletim sistemini tek bir işlevde yazabilirsiniz ". Bu yanlış değil: ama aynı zamanda kullanışlı değil. İpucu hakkında: Uygulamanız değiştiğinde (yani özel bir impl'i değiştirmek istiyorsanız), test paketiniz yolunuza gireceği için (bunu yapmamanız gereken bir başarısız testiniz olacaktır).
Matt Messersmith

14

Birim testlerinin temel amaçlarından birinin, programınızın iç kısımlarını yeniden düzenleyebileceğiniz ve daha sonra işlevselliğini bozmadığınızı doğrulayabildiğiniz göz önüne alındığında, birim testlerinizin bu kadar ince bir ayrıntı düzeyinde çalışması, program kodunda yapılacak herhangi bir değişiklik, testlerinizi yeniden yazmanızı gerektirir.


Cevabınızın neden reddedildiğinden emin değilim. Kısa, bu noktaya ve cevabı% 100 doğru alır.
David Arno

3
@DavidArno: Belki de özel yöntemlerin test edilmesinin test ayrıntı düzeyi ile pek bir ilgisi olmadığı için. Uygulama detaylarına bağlanma ile ilgili her şey var.
Robert Harvey

11

Özel yöntemler için birim testleri yazmak, birim testlerinizi uygulama ayrıntılarına bağlar.

Birim testleri, sınıfın dış yüzeyindeki (genel API'sı) bir sınıfın davranışını test etmelidir. Birim testleri, bir sınıfın iç kısımları hakkında hiçbir şey bilmek zorunda olmamalıdır. Bir sınıfın uygulama ayrıntılarına karşı birim testleri yazmak, yeniden düzenleme zamanı geldiğinde ellerinizi bağlar. Yeniden düzenleme neredeyse kesinlikle bu testleri kıracak, çünkü kararlı API'nizin bir parçası değiller.

Dedi ki, neden olabilir size özel yöntemleri için birim testleri yazmak ister misin?

Birim testleri ve artımlı gelişim arasında doğal bir gerilim vardır. Bir REPL (okuma-değerlendirme-yazdırma döngüsü) kullanan yazılım geliştiricileri, bir sınıfı veya işlevi "büyüttüğünüzde" küçük işlevsellik parçalarını hızlı bir şekilde yazmanın ve test etmenin ne kadar verimli olabileceğini kanıtlayabilir. Bunu birim test odaklı ortamlarda yapmanın tek iyi yolu, özel yöntemler için birim testleri yazmaktır, ancak bunu yaparken çok fazla sürtünme vardır. Birim testlerinin yazılması zaman alır, test etmek için gerçek bir yönteme ihtiyacınız vardır ve test çerçevenizin harici API'nizi kirletmemesi için yöntemi gizli tutma yeteneğini desteklemesi gerekir.

C # ve .NET gibi bazı ekosistemlerin REPL benzeri ortamlar oluşturma yolları vardır (Linqpad gibi araçlar bunu yapar), ancak projenize erişiminiz olmadığı için yardımcı programları sınırlıdır. Visual Studio'daki ilk pencere elverişsizdir; hala tam Intellisense'e sahip değil, içinde tam nitelikli isimler kullanmanız gerekiyor ve her kullandığınızda bir yapı tetikliyor.


4
@ user949300 Gerçek Scotsman yanılgısına düşmeden bunu tartışmak biraz zor , ama her türlü kötü yazılmış test var. Birim testi açısından, dahili uygulama ayrıntılarını bilmeden yönteminizin genel sözleşmesini test etmelisiniz. Belirli bir bağımlılığın X kez olarak adlandırıldığını iddia etmek her zaman yanlış değildir: bunun mantıklı olduğu durumlar vardır. Bunun, test edilen birimin sözleşmesinde gerçekten iletmek istediğiniz bir bilgi olduğundan emin olmanız gerekir.
Vincent Savard

3
@DavidArno: [shrug] Bunu bir süredir yapıyorum. Özel yöntemler için birim testleri, Microsoft test çerçevelerinde proxy nesnelerini desteklemeyi durdurmaya karar verene kadar her zaman benim için iyi çalıştı. Sonuç olarak hiçbir şey patlamamıştır. Özel bir yöntem için test yazarak evrende asla bir delik açmadım.
Robert Harvey

2
@DavidArno: Neden internetteki birisinin herhangi bir gerekçe sunmadan kötü bir fikir olduğunu söylediği için bana fayda sağlayan mükemmel derecede iyi bir teknik kullanmayı bırakayım?
Robert Harvey

2
Ünite testlerinden elde ettiğim temel fayda, bana kodumu değiştirmeme izin veren bir "güvenlik ağı" vermektir ve yaptığım değişikliklerin gerileme getirmediğinden emin olmaktır. Bu amaçla, özel yardımcı yöntemleri test etmek, bu tür gerilemeleri bulmayı kolaylaştırır. Özel bir yardımcı yöntemi yeniden düzenlediğimde ve bir mantık hatası eklediğimde, o özel yönteme özgü testleri kesiyorum. Birim testlerim daha genel olsaydı ve yalnızca bu kod biriminin arayüzünü test etseydi, problemi bulmak çok daha karanlık olurdu.
Alexander - Monica'yı eski

2
@Frax Tabii ki yapabilirdim, ama bu mantıkla sistem çapında entegrasyon testleri lehine birim testlerinden vazgeçmeliyim. Sonuçta, "çoğu durumda aynı davranışı test etmek için bu testleri değiştirebilmelisiniz"
Alexander - Reinstate Monica

6

Deneyimlerime göre, iç sınıfları test eden birimin, yöntemlerin genellikle test edilen işlevleri, sınıfları dışarı almam gerektiği anlamına geldiğini buldum. Başka bir soyutlama seviyesi oluşturmak için.

Bu, Tek Sorumluluk İlkesine daha iyi uyulmasına yol açar.


Bu kabul edilen cevap olmalı.
Jack Aidley

0

Bunun iyi bir soru olduğunu düşünüyorum, çünkü test kapsamında yaygın bir sorun ortaya koyuyor. Ancak iyi bir cevap, sorunun tam olarak doğru olmadığını söylemelidir, çünkü teoride, özel yöntemleri birim olarak test edemezsiniz . Bu yüzden özeldirler .

Belki daha iyi bir soru "Özel yöntemleri test etmek istediğimde ne yapmalıyım?" ve yanıt biraz açıktır: bunları testi mümkün kılan bir şekilde ortaya koymalısınız. Şimdi, bu mutlaka yöntemi herkese açık hale getirmeniz gerektiği anlamına gelmez ve budur. Büyük olasılıkla daha yüksek soyutlama yapmak isteyeceksiniz; testlerinizi ana API'nizdeki işlevi göstermeden o kitaplık üzerinde yapabilmeniz için farklı bir kitaplığa veya API'ya gidin.

Yöntemlerinizin farklı erişilebilirlik düzeylerine sahip olmasının bir nedeni olduğunu unutmayın ve her zaman sonunda sınıflarınızın nasıl kullanılacağını düşünmelisiniz.



Sorumumda Python'un gizlilik kavramının doğru olmadığını ve gizli yöntemlerin basit bir şekilde listelenmediğini ancak adlarını bildiğinizde kullanılabileceğini
Serge Ballesta
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.