# Unit-Tests für private Methoden



## tfa (25. Jul 2008)

Wir hatten gerade eine kleine Diskussion über Unit-Tests von privaten Methoden.
Es gibt hier zwar einige Möglichkeiten, aber keine ist so richtig toll. Wie macht man das? 

1. *Gar nicht.* Es wird nur die öffentliche Schnittstelle getestet (Blackbox). Private Methoden werden dabei indirekt mitgetestet.
2. *Keine privaten Methoden verwenden.* Alle Methoden sind mindestens Package-protected, die Unit-Tests befinden sich im selben Paket.
3. *Über innere Klassen.* Die zu testende Klasse beinhaltet eine innere Testklasse. Die class-Dateien kann man bei Deployment ausklammern.
4. *Über Reflection.*

zu 1: Grundsätzlich sicherlich richtig, aber es ist allerdings nicht immer praktikabel. Manchmal will man eine umfangreiche Methode
in viele kleine (private) aufteilen. Warum dann nicht auch die testen? Es ist ja viel einfacher, möglichst kleine Units zu behandeln
als große - z.B. die Erzeugung der Testdaten, Testabdeckung ist leichter herzustellen usw. Nachteil wäre ein höherer Aufwand beim Refactoring.

zu 2: Verletzt Kapselung und Geheimnisprinzip. Kommt für mich nicht in Frage.

zu 3: Auch schlecht. Ich möchte keine Tests in meinen Klassen.

zu 4: Unschön zu programmieren, aber mit ein paar Hilfsmethoden wird's schon gehen. Ist wohl die beste Lösung.

Wie macht ihr das?


----------



## ARadauer (25. Jul 2008)

ich bin für 1.
wenn ich meine ganzen public methoden teste müsste ich die private methoden auch erreichen. passiert das nicht, muss ich die paramter der aufrufe der public methoden so ändern, dass auch die private methoden erreicht werden.... schaff ich das nicht, ist die private mthede sinnlos..


----------



## FArt (25. Jul 2008)

In der Regel werden die privaten Methoden durch die anderen Methoden ausreichend implizit getestet, somit ist ein expliziter Test nicht notwendig.

Die Testabdeckung und die Qualität gibt einem dann Recht.
In Ausnahmefällen benutzen wir die vierte Variante, aber nur wenn diese Methode in einem Bereich vorkommt, in dem unverhältnismäßig viele (oder aufwendige) Mocks benötigt würden, damit das Teil sinnvoll außerhalb der angedachten Laufzeitumgebung funktioniert.


----------



## maki (25. Jul 2008)

Sehe 1. als richtig an, als alternative bleibt 4.
Blackbox ist wichtig, so bleibt man auch beim Testen von der IMplmentierung unabhängig.

protected Methoden sollten imho auch nicht getestet werden (so wie private), falls doch können die Testklassen im selben package liegen, was aber nicht heisst, dass sie im selben Quellcode Verzeichniss liegen müssen.


----------



## tfa (25. Jul 2008)

Ich denke auch in 95% der Fälle gilt Lösung 1. Im Moment habe ich nur einen der 5%-Fälle, mal sehen wie ich das mache.



> protected Methoden sollten imho auch nicht getestet werden (so wie private), falls doch können die Testklassen im selben package liegen, was aber nicht heisst, dass sie im selben Quellcode Verzeichniss liegen müssen.


Ich finde, die _veröffentliche_ Schnittstelle der Klasse muss getestet werden, und dazu gehören auch protected Methoden. Gerade bei Libs, APIs und Frameworks gibt es ja häufig Basisklassen, von denen der Klient eigene Klassen ableiten kann. Da ist ja nicht sicher gestellt, ob die protected Methode überhaupt jemals von einer public Methode (der Lib/API/Framework) aufgerufen wird. Also muss sie auch für sich getestet werden. Bei Individualsoftware sieht das natürlich anders aus.


----------



## maki (25. Jul 2008)

Ob sie aufgerufen werden sehe ich an der Testcoverage (Cobertura),  private & protected zu testen fühlt sich imho nicht richtig an, hab aber selber noch keine Frameworks veröffentlicht


----------



## Atze (25. Jul 2008)

hm, entweder check ich was nicht, oder die lösung liegt doch so nahe!  oder?

wie ardauer schon sagte, eigentlich sollen die privaten ja über die öffentlichen angesprochen werden, sonst werden die ja weder im test noch im live-betrieb angesprochen.

oder man baut sich halt ne öffentliche testmethode, die die privaten aufruft.

die philosophische frage, ob man das tun sollte ist ja ne andere, aber gehen tuts doch in jedem fall auch ohne reflection oder testklassen.

oder seh ich das problem echt nicht.


----------



## SlaterB (25. Jul 2008)

eine öffentliche Operation, die nur die private aufruft, geht schonmal gar nicht,
dann könnte man gleich die private public machen


----------



## Atze (25. Jul 2008)

ich rede nur vom testen, besser als gleich komplette testklassen zu erstellen


----------



## tfa (25. Jul 2008)

Versteh ich nicht. Du machst keine Testklassen sondern nur Testmethoden in deine "richtigen" Klassen?


----------



## maki (25. Jul 2008)

testMethoden in den zu testenden Klassen ist eigentlich völlig überholt...


----------



## Atze (25. Jul 2008)

anscheinend redet ihr von klassen / methoden, die permanent im code bleiben sollen
irgendwie hab ich das problem noch nicht genau verstanden, wies mir scheint.

1. warum sollte ich private methoden testen? denn wenn sie privat sind werden sie wohl von irgendeiner der öffentlichen methoden aufgerufen, und somit mitgetestet. wenn das nicht der fall ist, wird die methode sonst auch nie aufgerufen, und ich kann sie löschen -> also brauch ich sie nicht testen.

2. wenn ich sie doch UNBEDINGT testen will, aber sie nicht öffentlich machen will und benutzt wird sie im code auch nie (also nie automatisch aufgerufen), dann muss ich wohl über umwege ran. (obwohl ich mich frage, warum nie benutzte methoden getestet werden sollten!?)

mögliche umwege: ich erstelle testklassen oder baue öffentliche testmethoden!

testklassen wäre zwar oop-mäßig sinnvoller, aber um nur mal eben ne private methode aufzurufen zu viel aufwand. warum nicht einfach ne öffentliche methode? die kann ich ja nachher wieder entfernen. oder lasst ihr eure testklassen drin?   ???:L


----------



## byte (25. Jul 2008)

Atze hat gesagt.:
			
		

> 1. warum sollte ich private methoden testen? denn wenn sie privat sind werden sie wohl von irgendeiner der öffentlichen methoden aufgerufen, und somit mitgetestet. wenn das nicht der fall ist, wird die methode sonst auch nie aufgerufen, und ich kann sie löschen -> also brauch ich sie nicht testen.


Wenn Du einen komplexen Algorithmus schreibst und diesen in viele private Methoden aufteilst, dann kann es schon Sinn machen, diese auch separat zu testen. Du siehst im Fehlerfall dann wesentlich schneller, an welcher Stelle der Algorithmus auf die Nase fliegt.



			
				Atze hat gesagt.:
			
		

> testklassen wäre zwar oop-mäßig sinnvoller, aber um nur mal eben ne private methode aufzurufen zu viel aufwand. warum nicht einfach ne öffentliche methode? die kann ich ja nachher wieder entfernen. oder lasst ihr eure testklassen drin?   ???:L


Natürlich bleiben die Tests drin. :shock: Das ist doch grade der Sinn der Sache: man erweitert die Funktionalität und kann jederzeit überprüfen, ob durch Seiteneffekt evtl. bestehende Funktionalität zerschossen wurde.
Für Wegwerfcode brauche ich keinen Unittest zu schreiben. Da würde auch ne Main-Methode mit ein paar System.outs reichen (wie es wohl jeder gemacht hat, als man mit Programmieren anfing hehe).


----------



## Atze (25. Jul 2008)

dann kannst du auch deine testmethoden drin lassen!  immernoch weniger arbeit als klassen dafür zu erstellen.  oder?


----------



## byte (25. Jul 2008)

???

Ich schreibe keine Testmethoden in meinen Business-Objekten. Ich schreibe nur Unit- / Integrations-Tests und die liegen (natürlich) in separaten Klassen. Das hat in den richtigen Klassen nichts zu suchen und soll ja auch nicht mit ausgeliefert werden.

Es geht ja auch nicht darum, ob es Arbeit macht zu testen (im übrigen dauert das Erstellen einer Klasse nicht länger als das erstellen einer Methode). Das testen Arbeit macht, ist wohl klar. Aber noch mehr Arbeit macht es, gar nicht zu testen.


----------



## maki (25. Jul 2008)

Atze hat gesagt.:
			
		

> dann kannst du auch deine testmethoden drin lassen!  immernoch weniger arbeit als klassen dafür zu erstellen.  oder?


Sag mal Atze, hast du denn Erfahrung mit Testframeworks (JUnit, TestNG, etc. pp.)?

Nicht böse sein, aber deine Aussagen hören sich nicht gerade danach an... dann wäre es wohl danaben hier Ratschläge zu geben und Verwirrung zu stiften...


----------



## Atze (25. Jul 2008)

ich habe wenig erfahrungen mit testcases, das stimmt. lediglich mit junit hab ich 2 mal gearbeitet.
deswegen sag ich ja, ich versteh euer problem nicht ganz, bzw kann da nicht so nachvollziehen, weil ich noch nicht vor dem problem stand.

ich dachte es geht hier lediglich um die frage, wie man private methoden mittesten kann / sollte

für mich gibt es dieses problem in dem sinne nicht, da die privaten methoden ja immer durch die öffenltichen aufgerufen werden (sollten), daher ist es doch nur notwendig die öffentlichen zu testen. egal mit welcher testumgebung

wollte mich ja hier auch nicht mit viel erfahrung einbringen, nur die gedanken, die mir bei lesen des posts gekommen sind, teilen! 

sorry wenns nicht sehr produktiv war


----------



## byte (25. Jul 2008)

Wenns danach geht, kann ich auch nur die Main-Methode meiner Anwendung testen. Die ruft implizit alle Methoden meiner Anwendung auf.


----------



## maki (25. Jul 2008)

Schon OK, ist nur verwirrend wenn nicht alle vom selben reden.. Also nix für ungut 

Ich teile deine Ansicht dass private/protected Methoden/Klassen nicht direkt getestet werden sollten, habe ich bis jetzt nicht gemacht/gebraucht. Ich gehe vom Fall aus das internas gar nicht getestet werden sollen, also sog. "Blackbox testing", was drinnen genau passiert ist unwichtig, solange hinten das richtige rauskommt.
Damit kann man die interaktion von Objekten testen, anstatt interne Zustände(!), so richtet man das Design auf die Schnittstelle aus und weg von der Imlementierung.
Um Code richtig testen zu können, muss der Code ein gutes Design aufweisen, im nachhinein geht das nicht immer so schön...

UnitTests sind imho besser als geschnittenes Brot, speziell wenn man sie mit TDD (Test Driven Design) einsetzt, Kent Beck hat da ein sehr gutes Buch rausgebracht (TDD by Example), kann ich nur weiterempfehlen.
Bei TDD wird aus dem Testen zur Verifikation ein testen um zu Designen(!), denn zuerst kommt der Test, danach die zu testende Implementierung, und wenn die Tests bestehen, refactored man, hört sich schräg an, ist aber wirklich saugeil *g*

Gutes Video zu Tests im allgemeinen: http://www.youtube.com/watch?v=Pq6LHFM4JvE
(Die Stunde lohnt sich)


----------



## Atze (25. Jul 2008)

danke für die tipps, das video werd ich mir in ner ruhigen stunde mal antun.


----------



## didjitalist (26. Jul 2008)

tfa hat gesagt.:
			
		

> 1. *Gar nicht.* Es wird nur die öffentliche Schnittstelle getestet (Blackbox). Private Methoden werden dabei indirekt mitgetestet.


Genau das ist meiner Ansicht nach die einzig sinnvolle Variante. Unit Tests sollen die Funktionalität eines Moduls testen und nicht die Implementierung. Und dazu ist es hinreichend, das öffentliche interface einer Klasse zu testen. Kapselung ist ein wichtiger OO-Aspekt, der auch bei Tests einzuhalten ist. Es sollte einem Entwickler jederzeit offen stehen, die Implemtierung einer Klasse völlig umzukrempeln. Was der Unit Test dann leisten soll ist zu testen, ob die Klasse sich nach der Änderung noch genauso verhält, wie sie es vor der Änderung getan hat. Dazu sind interne Details - wozu private Methoden eindeutig gehören - völlig ohne Belang.


----------



## Atze (28. Jul 2008)

word!


----------



## Saxony (30. Jul 2008)

Hiho,

ich lese gerade "Unit-Test mit JUnit" von A. Hunt und D. Thomas und bin da über Kapitel 8 "Testen im Projekt" gestolpert.
Als ich das las, fiel mir ein, dass hier im Forum ja mal jemand so etwas wissen wollte.

Also die Autoren selber schreiben dazu:



			
				Unit-Tests mit JUnit hat gesagt.:
			
		

> Generell will man ja keine Kapselung aufbrechen, nur um dann besser testen zu können. Meist wird man eine Klasse testen, indem man ihre öffentlichen (public) Methoden ausführt. Wenn sich ein bedeutender Teil der Funktionalität hinter privaten und geschützten Methoden (private und protected) verbirgt, ist das vielleicht auch ein Warnsignal, dass eine weitere Klasse drinsteckt, die darum kämpft, herauszukommen. Wenn es doch nicht anders geht, ist es aber sicherlich besser, bei getestetem, funktionierendem Quelltext die Kapselung aufzuweichen, als bei ungetestetem, nicht-funktionierendem Quelltext.



Bezüglich der hier angesprochenen Thematik des Testens privater Methoden, wird folgender Vorschlag gemacht.

Und zwar schreibt man zu seiner Klasse "MyClass" eine Klasse "MyClassForTesting", welche von "MyClass" erbt. Die entsprechenden Methoden werden hier noch einmal neu und öffentlich/geschützt implementiert.

Naja - wollt ich nur noch einmal zum Besten geben!

bye Saxony


----------



## FArt (30. Jul 2008)

Saxony hat gesagt.:
			
		

> Und zwar schreibt man zu seiner Klasse "MyClass" eine Klasse "MyClassForTesting", welche von "MyClass" erbt. Die entsprechenden Methoden werden hier noch einmal neu und öffentlich/geschützt implementiert.
> 
> bye Saxony



Von finalen Klassen kann ich nicht ableiten und selbst wenn, ich muss ja immer den privaten Code duplizieren. Dann doch lieber per Reflection...


----------



## Saxony (30. Jul 2008)

maki hat gesagt.:
			
		

> UnitTests sind imho besser als geschnittenes Brot, speziell wenn man sie mit TDD (Test Driven Design) einsetzt, Kent Beck hat da ein sehr gutes Buch rausgebracht (TDD by Example), kann ich nur weiterempfehlen.
> 
> Gutes Video zu Tests im allgemeinen: http://www.youtube.com/watch?v=Pq6LHFM4JvE
> (Die Stunde lohnt sich)



Das Buch hab ich heute mal bestellt - ebenso wie das Buch "XUnit Test Patterns and Smells" von dem Autor siehe youtube-Video. Mal schauen was der zum testen von private Methoden meint. 

bye Saxony


----------



## SnooP (30. Jul 2008)

Ich denke bei aufwändigen Algorithmen, kann es durchaus Sinn machen, diese in protected Methoden zunächst zu testen... wenn man eine hinreichende Stabilität erreicht hat, kann man die notwendigen Methoden private machen und aufgrund der Erfahrung mit dem Testen dann entsprechende Eingangsparameter mitnehmen, so dass man quasi die kritischen Zustände der zu testenden Klasse für späteres Testen über eine public-Methode noch kennt...
ich hatte in einem früheren Projekt auch mal so eine Methode, die einfach praktischerweise fürs Testen protected war, auch wenn ich sie sonst eher private gemacht hätte... in dem Fall hätte man den Algorithmus auch prima über eine abgeleitete Klasse nochmals austauschen können, so dass das protected im Nachhinein sogar Sinn gemacht hat  ... 

ansonsten find ich, dass man schon mit dem Testen von public-Methoden genug zu tun hat  - man sollte es also nur in wenigen Fällen damit übertreiben...


----------

