Soru Özel bir işlevi veya özel yöntemleri, alanları veya iç sınıfları olan bir sınıfı nasıl sınarım?


İç özel yöntemleri, alanları veya yuvalanmış sınıfları olan bir sınıfı nasıl sınama (xUnit kullanarak)? Ya da sahip olunan özel bir işlev iç bağlantı (static C / C ++) veya özel bir (anonim) isim alanı?

Bir testi veya işlevi çalıştırmak için erişim düzenleyicisini değiştirmek sadece bir test yapmak için kötü görünüyor.


2268


Menşei


Özel bir yöntemi test etmenin en iyi yolu, doğrudan test etmemek - Surya
Makaleyi kontrol et JUnit ve SuiteRunner ile Özel Yöntemlerin Test Edilmesi. - Mouna Cheikhna
Katılmıyorum. Anlaşılması uzun ya da zor olan bir (kamu) yöntemi yeniden gözden geçirilmelidir. Sadece halka açık olanın yerine aldığınız küçük (özel) yöntemleri test etmemek gerekir. - Michael Piefel
Görünürlük aptal olduğu için herhangi bir yöntemi test etmiyor. Ünite testi bile en küçük kod parçası olmalı ve eğer sadece kamu yöntemlerini test ederseniz, hata oluştuğu zamandan emin olmayacaksınız - bu yöntem veya başka bir şey. - Dainius
Dersi test etmeniz gerekiyor işlevselliğideğil uygulama. Özel yöntemleri test etmek ister misin? Onları arayan kamu yöntemlerini test edin. Sınıfın sunduğu işlevsellik iyice test edilirse, iç tarafının doğru ve güvenilir olduğu kanıtlanmıştır; İç koşulları test etmeniz gerekmez. Testler test edilen sınıflardan dekuplajı korumalıdır. - Calimar41


Cevaplar:


Bir çeşit mirasınız varsa Java uygulama ve yöntemlerin görünürlüğünü değiştiremezsiniz, özel yöntemleri test etmenin en iyi yolu kullanmaktır yansıma.

Dahili olarak almak / ayarlamak için yardımcıları kullanıyoruz private ve private static değişkenler yanı sıra çağırmak private ve private static yöntemleri. Aşağıdaki modeller özel yöntemler ve alanlar ile ilgili hemen hemen her şeyi yapmanıza izin verecektir. Tabi ki değişemezsin private static final değişkenler yansıma yoluyla.

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Ve alanlar için:

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Notlar:
  1. targetClass.getDeclaredMethod(methodName, argClasses) içine bakmanızı sağlar private yöntemleri. Aynı şey için de geçerlidir    getDeclaredField.
  2. The setAccessible(true) özel kişilerle oynamak için gereklidir.


1417



Belki de API'yi bilmiyorsanız kullanışlıdır, ancak bu şekilde özel yöntemleri test etmeniz gerekiyorsa tasarımınızla ilgili bir şey var. Başka bir poster olarak, ünite testinin sınıfın sözleşmesini test etmesi gerektiğini söyler: sözleşme çok genişse ve sistemin çok fazla örneğini oluşturuyorsa tasarım ele alınmalıdır. - andygavin
Çok kullanışlı. Bunu kullanarak, testler tıkanıklıktan geçmişse kötü bir şekilde başarısız olacağını akılda tutmak önemlidir. - Rick Minerich
Örnek kod benim için çalışmadı, ancak bu daha net oldu: java2s.com/Tutorial/Java/0125__Reflection/... - Rob
Yansıma kullanmanın çok daha iyi olması, bunun gibi bir kütüphane kullanmaktır. Powermock. - Michael Piefel
Bu nedenle Test Tahrikli Tasarım yararlıdır. Davranışı doğrulamak için nelerin açığa çıkarılması gerektiğini anlamanıza yardımcı olur. - Thorbjørn Ravn Andersen


Özel bir yöntemi test etmenin en iyi yolu başka bir kamu yöntemidir. Bu yapılamazsa, aşağıdaki koşullardan biri doğrudur:

  1. Özel yöntem ölü koddur
  2. Test ettiğiniz sınıfa yakın bir tasarım kokusu var.
  3. Test etmeye çalıştığınız yöntem gizli olmamalıdır

507



Katılmıyorum. Bir sınıfın genel arayüzleri aracılığıyla pratikten daha fazla birim testine ihtiyaç duyan özel bir yöntemde bir algoritmaya sahip olmak tamamen geçerli. - Mr. Shiny and New 安宇
Hey Bay Shiny Evet, ama o zaman kırılgan testlerin olacak. Ayrıca, cevabımda 2 numaralı bölüme bakın. - Trumpi
Gevrek bir test, kodda bir değişiklik olduğunda çok kolay bir şekilde başarısız olan bir testtir. Genel olarak, bu, test sonucunun, beklenen girdi ve yöntemin bir dizi girdi verildikten sonra ne yaptığını temel almasıyla olur. İdeal olarak, sonuçları değiştirmeyen koddaki bir değişiklik testi bozmamalıdır. - aro_biz
@Bay. Parlak ve Yeni: Özel yönteminiz bağımsız birim testi gerektirecek kadar karmaşıksa, kendi sınıfına sahip olacak kadar karmaşıktır. Sınıf, elbette dahili olabilir (yani diğer paketlerden erişilemez). - sleske
@sleske, ben aynı fikirde değilim. Tasarım gereği özel olarak ihtiyaç duyduğunuz küçük bir özel yönteme sahip olabilirsiniz. ve her bir küçük kod parçasını test etmeyi tercih ederim. Bu test yöntemi bir bileşen testine doğru gidecektir. - despot


Bir sınıfta, özel yöntemleri doğrudan test etme gereği duyduğum kadar karmaşık olan özel yöntemlerim olduğunda, bu bir kod kokusu: Sınıfım çok karmaşık.

Bu gibi konulara değinmek için alışılagelen yaklaşımım, ilginç bitleri içeren yeni bir ders çıkarmaktır. Çoğunlukla, bu yöntem ve etkileştiği alanlar ve belki başka bir yöntem veya iki yeni bir sınıfa çıkarılabilir.

Yeni sınıf bu yöntemleri 'kamu' olarak sergiliyor, böylece birim testi için erişilebilir durumdalar. Yeni ve eski sınıflar artık hem orijinal sınıftan daha basit, hem de benim için harika (Ben işleri basit tutmalıyım, yoksa kaybolurum!).

İnsanların beyinlerini kullanmadan sınıflar oluşturmasını önermediğimi unutmayın! Buradaki nokta, iyi yeni sınıflar bulmanıza yardım etmek için birim test etme güçlerini kullanmaktır.


272



Soru, özel yöntemlerin nasıl test edildiğiydi. Bunun için yeni bir sınıf yapacağınızı söylüyorsunuz (ve daha fazla karmaşıklık ekleyin) ve yeni sınıf oluşturmamanızı önerdikten sonra. Peki özel yöntemleri nasıl test edersiniz? - Dainius
Yönteme sahipseniz, bu yöntemi test edebilmek için başka bir sınıf oluşturmaya gerek olmadığını düşünüyorum. Sınıf tasarımının burada sorgulandığını sanmıyorum. Bu yüzden, yazarın her şeyin doğru bir tasarıma sahip olduğunu düşündüğümden, bu yüzden karmaşıklığı artıran tek bir yöntem için başka bir sınıfın kullanılmasını kabul ediyorum. Tabii ki, yeterince karmaşık programınız olduğunda, açık bir hata olmayacaktır .. - Dainius
@Dainius: Yeni bir sınıf oluşturmayı önermiyorum sadece böylece bu yöntemi test edebilirsiniz. Yazma testlerinin tasarımınızı geliştirmenize yardımcı olabileceğini öneriyorum: iyi tasarımların test edilmesi kolaydır. - Jay Bazuzi
Fakat iyi bir OOD'un, sadece bu sınıf / nesne için doğru bir şekilde çalışması gereken yöntemleri ortaya çıkaracağını kabul ediyorsunuz? diğer herkes özel / protectec olmalıdır. Yani bazı özel yöntemlerde bazı mantık ve bu yöntemleri test IMO sadece yazılım kalitesini artıracaktır. Elbette, bir parça kod karmaşıksa, ayrı yöntemlere / sınıfa bölünmesi gerektiğine katılıyorum. - Dainius
@Danius: Yeni bir sınıf eklemek, çoğu durumda karmaşıklığı azaltır. Sadece ölç. Bazı durumlarda test edilebilirlik OOD'a karşı savaşır. Modern yaklaşım, lehte test edilebilirliktir. - AlexWien


Kullandım yansıma Java için bunu geçmişte yapmak için ve bence bu büyük bir hataydı.

Kesinlikle konuşmalısın değil Özel yöntemleri doğrudan test eden birim testler olmak. Sen ne meli test olmak, sınıfın diğer nesnelerle sahip olduğu kamu sözleşmesidir; Bir nesnenin içsellerini asla doğrudan test etmemelisiniz. Başka bir geliştirici, sınıftaki kamu sözleşmesini etkilemeyen, sınıf için küçük bir iç değişiklik yapmak isterse, o zaman, çalışmasını sağlamak için yansıma tabanlı testinizi değiştirmelidir. Bunu bir proje boyunca tekrar tekrar yaparsanız, ünite testleri daha sonra kod sağlığının yararlı bir ölçümünü yapmayı bırakır ve geliştirme için bir engel olmaya ve geliştirme ekibine bir can sıkmaya başlar.

Bunun yerine, yazdığınız birim sınamalarının özel yöntemlerle kodun düzgün bir şekilde sağlanmasını sağlamak için Cobertura gibi bir kod kapsamı aracı kullanmanız önerilir. Bu şekilde, özel yöntemlerin neler yaptığını dolaylı olarak test edersiniz ve daha yüksek bir çeviklik seviyesini korursunuz.


229



Buna +1. Bence bu soruya en iyi cevap. Özel yöntemleri test ederek, uygulamayı test ediyorsunuz. Bu, bir sınıf sözleşmesinin girdilerini / çıktılarını test etmek olan birim testinin amacını ortadan kaldırır. Bir test yapmalı bir tek Bağımlılıkları üzerine çağıran yöntemlerle alay etmek için uygulama hakkında yeterli bilgi sahibi olur. Daha fazla bir şey yok. Testinizi değiştirmek zorunda kalmadan uygulamanızı değiştiremezseniz, test stratejiniz zayıftır. - Colin M
@Colin M Bu gerçekten sorduğu şey değil;) Ona karar versin, projeyi bilmiyorsun. - Aaron Marcus
Gerçekten doğru değil. Özel yöntemin küçük bir bölümünü kullanarak kamu yöntemiyle test etmek çok çaba gerektirebilir. Özel yönteminizi çağıran satıra ulaşmadan önce, kamu yöntemi önemli bir kurulum gerektirebilir - ACV


Bu yazıda: JUnit ve SuiteRunner ile Özel Yöntemlerin Test Edilmesi (Bill Venners), temelde 4 seçeneğiniz var:

  • Özel yöntemleri test etme.
  • Yöntem paketi paketi verin.
  • Yuvalanmış bir test sınıfı kullanın.
  • Yansıma kullanın.

187



@ user86614 Test kodunu üretim koduna koymak iyi bir fikir değildir. - Jimmy T.
@JimmyT., "Üretim kodu" kimin için olduğuna bağlı. Hedef kullanıcılar sistem kodu olmak üzere VPN içerisinde bulunan uygulamalar için üretilen kodu çağırırdım. - Pacerier
@Pacerier Ne demek istiyorsun? - Jimmy T.
Yukarıda belirtildiği gibi 5 seçenek, özel yöntemi çağıran kamu yöntemini sınamaktadır? Doğru? - user2441441
@LorenzoLerate Bunun ile güreştim çünkü gömülü gelişim yapıyorum ve yazılımımın olabildiğince küçük olmasını istiyorum. Boyut kısıtlamaları ve performans düşünebilmemin tek nedenidir.


Genel olarak bir birim testi, bir sınıfın veya birimin genel arayüzünü kullanmak üzere tasarlanmıştır. Bu nedenle, özel yöntemler açık bir şekilde test etmeyi beklemediğiniz uygulama detayıdır.


96



Bu IMO'nun en iyi cevabı ya da genellikle söylendiği gibi, test davranışları değil, yöntemlerdir. Birim testi, kaynak kod metrikleri, statik kod analiz araçları ve kod incelemeleri için bir değişiklik değildir. Özel yöntemler, testleri ayırmak zorunda kaldıkları kadar karmaşıksa, muhtemelen daha fazla sınama yapılmasına değil, yeniden gözden geçirilmesi gerekir. - Dan Haynes
Öyleyse özel yöntemler yazmayın, sadece 10 tane daha küçük sınıf oluşturun? - razor


Özel bir yöntemi test etmek istediğim iki örnek:

  1. Şifre çözme rutinleri - Ben istemem Sadece görmek istedikleri herkese görünür hale getirmek istiyorum sınama uğruna, başka herkes şifresini çözmek için bunları kullanın. Ama onlar kod için içsel, karmaşık, ve her zaman işe yaraması gerekir (bariz istisna, çoğu durumda özel yöntemleri bile görmek için kullanılabilecek yansımadır) SecurityManager bunu önlemek için yapılandırılmamış).
  2. SDK oluşturma topluluk için tüketimi. İşte kamu alır bir bu yana tamamen farklı anlam tüm dünyanın görebileceği koddur (sadece başvuruma dahil değil). Koydum yapmazsam özel yöntemlere kod SDK kullanıcılarının bunu görmesini istiyorum - I Bunu sadece kod kokusu olarak görmüyorum SDK programlama nasıl çalışır. Ama Tabii ki hala test etmek zorundayım özel yöntemler ve onlar nerede SDK'mın işlevselliği aslında hayatları.

Sadece "sözleşmeyi" test etme fikrini anlıyorum. Ancak, birinin kodu test etmediğini göremiyorum - kilometreniz değişebilir.

Bu yüzden benim tradeoff'um güvenlik ve SDK'mdan ödün vermek yerine JUnits'i yansıtma ile karmaşıklaştırmayı içeriyor.


56



Test etmek için asla bir yöntem sunmamalısınız. private tek alternatif değil. Erişim değiştirici yok package private ve ünite testinizin aynı pakette kaldığı sürece test edebileceğiniz anlamına gelir. - ngreen
@ngreen hepsi doğru, ama sorunun ne olduğu değil. OP, özel yöntemleri test etmeyi sorar. Varsayılan özel ile aynı değildir; Belirtildiği gibi, aynı sınıfta sadece bu sınıfı bildirerek bir sınıftan varsayılan erişim yöntemini kolayca görebilirsiniz. Özel erişim ile, başka bir ballgame olan yansıma gerektirir. - Richard Le Mesurier
Cevabınızı, özellikle 1 numaralı noktayı, OP'yi değil. Sadece kamuya açık olmasını istemediğiniz için özel bir yöntem yapmaya gerek yoktur. - ngreen
@ngreen true thx - "public" kelimesiyle tembel davrandım. Yanıtı kamuya açık, korunan, varsayılan (ve yansımadan bahsetmek) içerecek şekilde güncelledim. Yapmaya çalıştığım nokta, bazı kodların gizli olması için iyi bir sebep olduğudur, ancak bu bizi test etmemizi engellememelidir. - Richard Le Mesurier
Herkese gerçek örnekler verdiğiniz için teşekkür ederiz. Çoğu cevaplar iyidir, ancak teorik bir bakış açısıyla. Gerçek dünyada, uygulamayı sözleşmeden gizlemek zorundayız ve hala test etmemiz gerekiyor. Bütün bunları okurken bence bu yeni bir test seviyesi olmalı, farklı bir isimle. - Z. Khullah


Özel yöntemler, genel bir yöntemle çağrılır, bu nedenle, genel yöntemlerinizdeki girdiler, bu genel yöntemlerle çağrılan özel yöntemleri de test etmelidir. Bir kamu yöntemi başarısız olduğunda, bu özel yöntemde bir başarısızlık olabilir.


53



Asıl gerçek. Sorun, bir kamu yönteminin birkaç özel yöntem çağırması gibi, uygulamanın daha karmaşık olduğu zamandır. Hangisi başarısız oldu? Ya da karmaşık bir özel yöntemse, maruz bırakılamaz veya yeni bir sınıfa aktarılamaz. - Z. Khullah
Özel yöntemin neden test edilmesi gerektiğini zaten belirttiniz. "O zaman olabilir" dedin, emin değilsin. IMO, bir yöntemin test edilmesi gerekip gerekmediğini, erişim seviyesine diktir. - Wei Qiu


Kullandığım diğer bir yaklaşım ise, özel ya da korunan paketlemek için özel bir yöntemi değiştirmek ve daha sonra @VisibleForTesting Google Guava kütüphanesinin ek açıklaması.

Bu, bu yöntemin herhangi bir şekilde dikkatli kullanılmasını ve bir pakette bile doğrudan erişmemesini söyleyecektir. Ayrıca bir test sınıfının aynı pakette olması gerekmez fiziksel olarakama aynı pakette Ölçek Klasör.

Örneğin, test edilecek bir yöntem varsa src/main/java/mypackage/MyClass.java o zaman test aramanız src/test/java/mypackage/MyClassTest.java. Böylece test sınıfınızda test yöntemine erişebilirsiniz.


30



Bunun hakkında bir şey bilmiyordum, bu da içten içe, hala bu tür bir anlamaya ihtiyacınız varsa, tasarım sorunlarınız olduğunu düşünüyorum. - Seb
Bana göre, bu yangın tatbikatını test etmek için yangın müdürüne bir defaya mahsus bir anahtar vermek yerine, kapının üzerindeki bir işaretle ön kapının kilidini bırakıyorsunuz - "test için kilitli değil - eğer siz değilseniz firmamız, lütfen girmeyin ". - Fr Jeremy Krieg


Eski kodları büyük ve ilginç sınıflarla test etmek için yazdığım bir özel (veya kamu) yöntemini test edebilmek genellikle çok faydalıdır. şimdi.

ben kullanıyorum junitx.util.PrivateAccessor- Java için paket. Özel yöntemlere ve özel alanlara erişmek için yararlı tek gömleklerin bir sürü.

import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);

28



Tüm JUnit-addons'ları indirdiğinizden emin olun (sourceforge.net/projects/junit-addons) Kaynak Forge-Önerilen Projesi PrivateAccessor değil. - skia.heliou
Ve emin olun ki, Class Bu yöntemlerde ilk parametreniz olarak, yalnızca siz erişiyorsunuz static üyeler. - skia.heliou