# JUnit - Auslassen von Code



## Jue (16. Feb 2019)

Hallo Java-Freunde,

ich teste gerade mit JUnit ein Projekt, bin da aber leider noch nicht so fit. Wie kann ich verhindern, dass während des Tests einer Methode Objektmethoden anderer Klassen aufgerufen werden, da dies logischerweise zu einer NullPointerException führt. Objekte dieser Klasse kann ich auch nicht initialisieren, da es sich um eine Controller-Klasse für ein FXML-Sheet handelt. 

Hier mal der Code dazu:


```
public void rotate() {
        // Berechnungen

        glc.paint(board); // Sollte nicht ausgeführt werden beim Test
        }
```

Die Junit-Testmethode zu rotate:


```
@Test
    void testRotate() {
        try {
            Class c = Class.forName("de.ubt.ai1.bp.bt705828.main.Tetris");
            Tetris t = (Tetris) c.newInstance();
           
            Method m = c.getDeclaredMethod("rotate", null);
            m.setAccessible(true);
            Tetromino tet = new Tetromino(0, Color.PURPLE, new int[][] {{1, 1, 0}, {0, 1, 1}});
            Tetromino tet2 = new Tetromino(4, Color.YELLOW, new int[][] {{0, 1}, {1, 1}, {1, 0}}); //rotated tet
            t.setX(0); t.setY(tet.getShape().length-1); t.setTetToPos(tet, t.getX(), t.getY()); t.setTetromino(tet);
            m.invoke(t, null);
            assertTrue(equal(tet2.getShape(), t.getTetromino().getShape()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
```

Vielen Dank für eure Hilfe!


----------



## Barista (17. Feb 2019)

Mocking


----------



## mihe7 (17. Feb 2019)

Jue hat gesagt.:


> Wie kann ich verhindern, dass während des Tests einer Methode Objektmethoden anderer Klassen aufgerufen werden


Ohne die Methode zu ändern: gar nicht. Du kannst nur das Objekt beeinflussen, dessen Methoden aufgerufen werden.



Jue hat gesagt.:


> Objekte dieser Klasse kann ich auch nicht initialisieren, da es sich um eine Controller-Klasse für ein FXML-Sheet handelt.


Dann solltest Du das Design Deiner Anwendung überdenken. Faustregel: guter Code ist leicht testbar. 

Eigentlich wollte ich es nur am Rande erwähnen, um Dich erst gar nicht in Versuchung zu führen, aber da @Barista es eh schon in den Ring geworfen hat: wenn es gar nicht anders geht, kannst Du Objekte auch mocken (s. mockito).



Jue hat gesagt.:


> Die Junit-Testmethode zu rotate:


Was willst Du denn mit Reflection in der Testmethode?


----------



## Jue (17. Feb 2019)

Erstmal danke! 



mihe7 hat gesagt.:


> Was willst Du denn mit Reflection in der Testmethode?



In diesem Fall brauche ich es gar nicht, stimmt. Aber ich hatte vorher private Methoden getestet und es dann bei dieser Methode gedankenverloren genauso gemacht.

Ich lasse dieser paint Methode immer dann aufrufen, wenn irgendwas mit einem Spielstein passiert ist. Sollte ich diesen Teil dieser Methoden entfernen und stattdessen eine extra Game Loop einführen, die diese Methode regelmäßig aufruft? Wenn ja, könnt ihr mir da im Ansatz weiterhelfen, wie ich das anstelle?


----------



## mihe7 (17. Feb 2019)

Jue hat gesagt.:


> Aber ich hatte vorher private Methoden getestet


Man testet keine privaten Methoden.



Jue hat gesagt.:


> Sollte ich diesen Teil dieser Methoden entfernen und stattdessen eine extra Game Loop einführen, die diese Methode regelmäßig aufruft?


Nein. Das kannst Du z. B. über das Observer-Pattern entkoppeln: die Observer registrieren sich bei Deinem Observable und das informiert die registrierten Observer.


----------



## White_Fox (17. Feb 2019)

mihe7 hat gesagt.:


> Man testet keine privaten Methoden.


Ist das wirklich so?


----------



## mrBrown (17. Feb 2019)

White_Fox hat gesagt.:


> Ist das wirklich so?


Ja. Warum etwas testen, was man's nicht mal aufrufen kann?


----------



## mihe7 (17. Feb 2019)

White_Fox hat gesagt.:


> Ist das wirklich so?


Sofern es sich nicht um toten Code handelt, wird die private Methode direkt oder indirekt über eine öffentliche Methode aufgerufen. Diese wird getestet und damit ist der Code der privaten Methode durch einen Test abgedeckt.

Wenn Du mit Unit-Tests Spaß haben willst, dann darfst Du Deine Tests nicht stur an Deinem Code ausrichten. Sonst musst Du bei jeder kleinen Änderung an der Klasse Deine Tests anpassen und das ist der Punkt, wo dann viele sagen: Unit-Tests sind Mist, die behindern mich ständig bei der Arbeit, der Aufwand ist mir zu hoch.


----------



## White_Fox (17. Feb 2019)

mrBrown hat gesagt.:


> Ja. Warum etwas testen, was man's nicht mal aufrufen kann?


Weil du z.B. eine private Methode hast die einige wichtige Überprüfungen erledigt, die intern von mehreren anderen Methoden aufgerufen wird. Wenn diese Methode nicht völlig korrekt funktioniert, funktioniert deine ganze Klasse nicht, allerdings kannst die Überprüfung von außen nicht genug testen bzw. wären Fehler recht weiträumig zu suchen.

Oder weil du ein oder mehrere innere Klassen einer Klasse separat testen willst. Vor allem, wenn sich dahinter verschiedene Threads verbergen die zwar unabhängig voneinander werkeln, aber z.B. Daten hintereinander verarbeiten.

Das waren jedenfalls Fälle, wo ich Reflexion in Unittests recht hilfreich fand. Ich bin zwar nur Hardwareentwickler und kein Softwerker und vielleicht war das einfach nur mies konstruierte Softwarearchitektur...keine Ahnung.

Ich denk mir aber, wenn man sehr restriktiv arbeitet, also möglichst alles privat und nur das absolut nötige öffentlich macht, kann es öfter mal sinnvoll sein wenn der Test mehr abdeckt als man öffentlich einsehen kann. Auch wenn der Test der öffentlichen Bereiche zwar in der reinen Theorie ausreichend sein sollte, so zeigt einem ein Unittest der tieferen Innereien schneller, was man z.B. kaputtoptimiert hat.


----------



## Jue (17. Feb 2019)

mihe7 hat gesagt.:


> Man testet keine privaten Methoden.



Ich denke schon. Ich war sehr bedacht auf eine saubere Verwendung der Sichtbarkeiten, aber die privaten Methoden stellen einen erheblichen Teil der Logik dar, der natürlich getestet werden muss.

Gibt es abseits des Observer Patterns keine Alternative? Ich muss das Projekt leider in Kürze submitten und mir fehlt die Zeit für ein komplettes Refactoring. Ich habe bei diesem Projekt auf jeden Fall viel gelernt und würde das Projekt im Nachhinein etwas anders strukturieren, z.B. eben auf gute Testbarkeit achten, aber bis zur Abgabe muss ich einfach noch ein paar sinnvolle Junit-Tests für meinen derzeitigen Code implementieren. 
Danke für eure Antworten auf jeden Fall!


----------



## mihe7 (18. Feb 2019)

Jue hat gesagt.:


> die privaten Methoden stellen einen erheblichen Teil der Logik dar, der natürlich getestet werden muss.


Ich antworte mit einem Zitat:


mrBrown hat gesagt.:


> Warum etwas testen, was man's nicht mal aufrufen kann?



Du kannst gerne mal ein Beispiel zeigen.



Jue hat gesagt.:


> Gibt es abseits des Observer Patterns keine Alternative? Ich muss das Projekt leider in Kürze submitten und mir fehlt die Zeit für ein komplettes Refactoring.


Zur Not kannst Du auch hergehen und einfach einen Setter für glc in Deine Klasse aufnehmen. Den rufst Du in Deinem Test mit einem gefakten glc auf.


----------



## mihe7 (18. Feb 2019)

White_Fox hat gesagt.:


> Wenn diese Methode nicht völlig korrekt funktioniert, funktioniert deine ganze Klasse nicht, allerdings kannst die Überprüfung von außen nicht genug testen bzw. wären Fehler recht weiträumig zu suchen.


Wenn Du untestbaren Code schreibst, besteht die Lösung nicht darin, Reflection zu verwenden, sondern den Code so umzuschreiben, dass er testbar wird. Was die Restriktionen angeht: es gibt nicht nur private und protected sondern auch package private.


----------



## mrBrown (18. Feb 2019)

White_Fox hat gesagt.:


> Wenn diese Methode nicht völlig korrekt funktioniert, funktioniert deine ganze Klasse nicht, allerdings kannst die Überprüfung von außen nicht genug testen bzw. wären Fehler recht weiträumig zu suchen.


Dann schreib deine Tests oder deine Methoden anders, wenn du sonst keine Fehler finden kannst.
Private Methoden testen zu müssen, ist nahezu immer ein Designproblem.



White_Fox hat gesagt.:


> Oder weil du ein oder mehrere innere Klassen einer Klasse separat testen willst. Vor allem, wenn sich dahinter verschiedene Threads verbergen die zwar unabhängig voneinander werkeln, aber z.B. Daten hintereinander verarbeiten.


Vermutlich sind dann innere Klassen das falsche Mittel, „unabhängig voneinander“ ist dafür immer ein sehr starkes Indiz.



Jue hat gesagt.:


> aber die privaten Methoden stellen einen erheblichen Teil der Logik dar, der natürlich getestet werden muss.


Wenn man solche Fälle hat, sind altbekannte Pattern oft ein passendes Mittel, passend _könnte_ hier zB Strategie-Pattern sein.


Jue hat gesagt.:


> mir fehlt die Zeit für ein komplettes Refactoring


frei nach Fowler: wenn ein Refactoring länger als ein paar Minuten dauert, ist es kein Refactoring mehr 



Jue hat gesagt.:


> aber bis zur Abgabe muss ich einfach noch ein paar sinnvolle Junit-Tests für meinen derzeitigen Code implementieren.


Du kannst natürlich auch private Methoden über Reflection testen, aber ob das dann sinnvolle Unittests sind? Bei mir würde man dafür Punktabzug bekommen, vermutlich mehr als für  weniger, aber dafür „bessere“ Tests.


----------



## White_Fox (18. Feb 2019)

mrBrown hat gesagt.:


> Vermutlich sind dann innere Klassen das falsche Mittel, „unabhängig voneinander“ ist dafür immer ein sehr starkes Indiz.


Sagen wir eher "laufzeitunabhängig", und vielleicht war es tatsächlich das falsche Mittel. Aber nur aus Neugier und weil ich gerne dazulerne: Wie hättest du es gemacht?

Es ging damals um die Kommunikation zwischen einem Rechner und einer echtzeitfähigen Hardware über einen SPI-USB-Wandler (von FTDI). Die Hardware hat alle 10ms ein Ausleseintervall verlangt. Da Echtzeit auf (insbesondere Windows-)PCs immer so eine Sache ist, hab ich die eigentliche Nachrichtenübermittlung in einen eigenen Thread gepackt und diesen von allen anderen sonstigen Aufgaben befreit, der enthielt dann wirklich nur: aktuelle Zeit nehmen, Nachrichten senden/empfangen, in einen Puffer ablegen, Restzeit abwarten.
Allerdings mußten die Nachrichten vor dem Senden noch transportfähig aufbereitet und die eingegangenen Nachrichten noch irgendwie verteilt werden (Beobachtermuster). Dafür gab es dann nochmal zwei Threads, damit die Kommunikation nicht blockiert wird.

Alle drei Threads hab ich in eine eigene Klasse gesteckt, das hat m.E. recht gut gepaßt da das zwar klar getrennte Aufgaben waren, diese jedoch untrennbar zum Zweck der äußeren Klasse gehört haben. Ich hätte diese zwar durchaus auch package private machen können, allerdings diese drei Threadklassen außerhalb der äußeren Klasse niemals irgendeine Daseinsberechigung gehabt, weshalb ich sie um einer sauberen Struktur willen als innere Klasse haben wollte.

Da ich mir so ziemlich alles, was Software angeht, selbst beigebracht habe: Wie hättest du das gemacht? 

Nachtrag:
Ursprünglich hatte ich gar nicht vor, die inneren Klassen zu testen. Ich hatte aber das Problem, daß ich an irgendeiner Stelle die Threads nicht sauber genug synchronisiert hab und irgendwo gelesen wurde während gleichzeitig geschrieben wurde. Das fiel erst in einem großen Gesamttest der Klasse auf. Die Tests habe ich dann geschrieben um zu sehen, ob jeder Thread brav wartet bis die Ressourcen frei sind. Mit den Tests ging das sehr gut, mit den herkömmlichen Debuggingmethoden kam ich da aber nicht mehr zurande.
/Nachtrag

Vielleicht noch etwas, wo ich weiß daß das auch nicht jeder so sieht:
Ich bin ziemlich pingelig, was eine klare Struktur angeht, das ist aber nicht auf Software beschränkt. Z.B. bei Schaltplänen bin ich ähnlich restriktiv. Weil garantiert ich es bin, der das Zeug nach einem halben Jahr oder noch längerer Zeit wieder anfassen muß weil etwas geändert werden oder ein Fehler beseitigt werden muß. Da will ich mit möglichst wenig Einarbeitung sehen was der Code machen soll. Innerhalb großzügiger Grenzen würde ich Codelesbarkeit auch jederzeit über Performance stellen (allein schon deshalb, weil ich es als Blödsinn erachte, in einer Hochsprache auf Performance zu achten -> die Compileroptimierung haut einem eh alles durcheinander). Zumindest bei Desktoprechnern sehe ich das so, und wenn man ernsthaft optimieren muß (Microcontroller oder vllt auch Serverkram) gibt es Assembler.

Ich stimme durchaus damit überein, daß guter Code meistens gut testbar ist. Ich finde allerdings nicht, daß sich die Programmstruktur an dessen Testbarkeit ausrichten sollte. Schließlich ist der Test nicht der Grund, warum man Code schreibt.
Ich stimme auch damit überein, daß, wenn der Test geändert werden muß (und die Gefahr besteht bei Test der privaten Innereien natürlich) man etwas richtig falsch gemacht hat, der Test sollte eigentlich nie geändert werden müssen. Da muß man dann abwägen was man flexibel halten oder festnageln will. Ich sehe das ähnlich wie die Diskussion um öffentliche Membervariablen. Ich nutze grundsätzlich Getter/Setter-Methoden (könnte ja sein man braucht doch irgendwann mal eine Eingangsprüfung), andere sehen das aufgrund ihrer Erfahrung, persönlichen Weltanschauung, ... eben anders.


----------



## mrBrown (18. Feb 2019)

White_Fox hat gesagt.:


> Da ich mir so ziemlich alles, was Software angeht, selbst beigebracht habe: Wie hättest du das gemacht?


Tendenziell ähnlich, und erstmal nur die Klassen in das Package hochgezogen.
Die drei beteiligten Klassen (Daten abholen, Daten transformieren, Daten verteilen) für sich sind ja unabhängig, die kann man also alle recht gut getrennt voneinander umsetzen und auch testen. Die klingen zumindest nur recht lose gekoppelt (Kommunikation über Puffer, wenn ich raten müsste irgendeine Queue?, und Beobachtermuster), dann kann man den Code ja auch recht gut trennen.



White_Fox hat gesagt.:


> Vielleicht noch etwas, wo ich weiß daß das auch nicht jeder so sieht:


Mindestens ich seh das auch so, und hier im Forum gibts auch noch ein paar andere 



White_Fox hat gesagt.:


> Ich stimme durchaus damit überein, daß guter Code meistens gut testbar ist. Ich finde allerdings nicht, daß sich die Programmstruktur an dessen Testbarkeit ausrichten sollte. Schließlich ist der Test nicht der Grund, warum man Code schreibt.


Test Driven Development sieht das anders


----------



## mihe7 (18. Feb 2019)

@White_Fox Ein Projekt, das ganz in die Richtung des Deinigen geht (allerdings RS232 und ohne Echtzeit-Anforderung), habe ich erst vor kurzem umgesetzt. Vereinfacht gibt es auch eine Reader-Klasse (die Bezeichnungen sind übrigens anders), die durch serielle Events aktiviert wird (1 Thread). Diese hat die Aufgabe, Datenpakete (Frames) von der seriellen Schnittstelle zu lesen und weiterzugeben. 

Dann gibt es eine Writer-Klasse, die Datenpakete über die serielle Schnittstelle rausschreibt. Die dritte Klasse bildet das Protokoll der Gerätefamilie ab - inkl. Observer-Pattern. 

Würde ich nun Reader/Writer in die Protokollklasse klatschen, hätte ich mehrere Probleme. Ich wüsste auch nicht, wozu. Ganz im Gegenteil: das High-Level-Protokoll hat mit dem Übertragungsweg nichts zu tun. Wenn morgen ein neues Modell ankommt, das nicht mehr via RS232 sondern nur noch via USB ansprechbar ist, wäre das kein Problem. Dann gibt es eben ein USB-Reader/-Writer-Paar und gut ist es. Das High-Level-Protokoll bleibt das selbe.

Was die Strukturierung von Klassen betrifft: dazu sind Pakete gerade da, Klassen eher weniger.

Übertragen auf Hardware machst Du folgendes: Du nimmst mehrere Komponenten, packst sie in ein Gehäuse und gießt dieses mit Kunststoff aus. Später willst Du die einzelnen Komponenten testen und bohrst daher erstmal wieder Löcher in das Gehäuse um an die Testpunkte der Komponenten ranzukommen. Das käme mir doch seltsam vor.


----------



## White_Fox (18. Feb 2019)

@mihe7 SPI und RS232 kannst du aber schlecht vergleichen. Bei RS232 wartest du einfach, bis Daten kommen und das wars. Bei SPI war mein Programm dafür verantwortlich, regelmäßig die Daten abzuholen da SPI nicht asynchron funktioniert. Ist halt ein Master-Slave-Protokoll.

Aber ansonsten:
Ich hatte schon eine eigene Klasse, die sich um das Protokoll so weit wie möglich gekümmert hat, das Ganze war nur noch etwas komplizierter. Jede Nachricht wurde in einem Nachrichtenframe untergebracht (das hat eine noch nicht erwähnte andere Klasse getan), aber diese Nachrichtenframes mußten noch zu einem Transferframe zusammengebaut werden (und das war die Aufgabe einer der inneren Klassen).

Ansonsten hinken die Vergleiche zwischen Hard- und Software doch ganz arg. Bei Hardware baut man in der Regel einen Prototypen und versieht direkt Meßpunkte wo man entweder mit dem Multimeter ran kann. Wenn man es sich leisten kann gerne auch mit einer Stiftleiste oder gar einer BNC- oder SMA-Buchse (für HF-Kram um ein Oszilloskop anzuschließen) bestückt und mit passender Beschriftung auf der Platine versehen. In der Serie bestückst du den Kram dann entweder nicht oder überarbeitest das Layout nochmal und schmeißt die Footprints dafür wieder raus.

Wenn man solche "Meßpunkte" in die Software integrieren würde...pfui. Dann doch lieber mit Reflections in den Eingeweiden wühlen. Und Alpha- oder Beta-Versionen sind nicht daß, was der Prototyp in der Hardware ist.

Im Übrigen: die fertige Kommunikationsklasse war, auch wenn kompliziert zu testen, sehr komfortabel in der Benutzung. Zum Senden gabs einfach eine Methode, die du mit einem Byte-Array und einer Enumeration (zur "Art der Nachricht", protokollbedingt) gefüttert hast-und das wars. Empfang über Observerpattern. Einfacher ging es nicht, so wollte ich es haben.
Und die Kommunikation selber wurde über eine Bibliothek, die ich irgendwo im Internet gefunden habe, hergestellt. 
Diese Bibliothek hab ich hinter einer Wrapperklasse versteckt für den Fall, daß ich eine andere Bibliothek verwenden will/muß. Um die Kommunikation herzustellen/zu ändern, wurde der Kommunikationsklasse einfach eine neue Wrapper-Instanz übergeben.

Das mit der Wrapperklasse war eigentlich nur eine Angstmaßnahme, weil ich die Bibliothek nicht kannte. Zum Testen war das aber wiederum sehr gut, da ich so die Hardware einfach mocken konnte.


----------



## mihe7 (18. Feb 2019)

White_Fox hat gesagt.:


> Bei RS232 wartest du einfach, bis Daten kommen und das wars. Bei SPI war mein Programm dafür verantwortlich, regelmäßig die Daten abzuholen da SPI nicht asynchron funktioniert. Ist halt ein Master-Slave-Protokoll.


Das regelmäßige Daten abholen kam bei mir auf höherer Ebene. Spielt aber auch keine Rolle: in jedem Fall hat man klar abgrenzbare Verantwortlichkeiten. 

Ich muss ein wenig schmunzeln: wenn ich Deine Software-Beschreibung lese, könnte es sich fast 1:1 um meine handeln  



White_Fox hat gesagt.:


> Ansonsten hinken die Vergleiche zwischen Hard- und Software doch ganz arg.


Dass Analogien vereinfachend und damit nie korrekt sind, ist klar. Trotzdem gilt, dass Du das Teil nicht erst vergießt, anschließend zum Testen Gewalt anwendest, um an die Innereien zu kommen. Nichts anderes ist Reflection: ein Werkzeug, das die Sprache (im Gegensatz zu anderen) zufällig bietet und ein Werkzeug, mit dem man z. B. an private Member herankommt. Was würdest Du denn machen, wenn es Reflection in Java nicht gäbe?


----------



## White_Fox (18. Feb 2019)

mihe7 hat gesagt.:


> Was würdest Du denn machen, wenn es Reflection in Java nicht gäbe?


Tja, das hab ich mich natürlich gefragt als ich vor dem Problem stand und von Reflection noch nichts wußte. Andere schrieben, daß sie z.B. zum Testen die Sichtbarkeitsmodifizierer anpassen, was für mich auch nicht in Frage kam.

Ich sags mal so, Java hat Reflection wohl nicht umsonst bekommen, und ich bin froh darum. 

Viel abenteuerlicher als Reflection in Tests finde ich Reflection aber in regulärem Programmcode (siehe Tableview). Für Testzwecke ist es ein tolles Werkzeug, aber in einem Framework fremde Klassen aufzubrechen und sich am Methodennamen entlangzuhangeln um damit regulär zu arbeiten...das ist doch abartig.


----------



## mihe7 (18. Feb 2019)

White_Fox hat gesagt.:


> Viel abenteuerlicher als Reflection in Tests finde ich Reflection aber in regulärem Programmcode (siehe Tableview).


Die Frage ist nicht, ob man Reflection verwendet, sondern warum man versucht, nach außen extra abgeschirmte Dinge zu testen. Ich kapsle doch nicht erst etwas, um hinterher über einen "Hack" die Kapselung aufzuheben. Das ergibt einfach keinen Sinn. 

Man kann Testfälle bereits aufstellen, bevor man auch nur eine Zeile Code geschrieben hat. Warum? Weil man die Erwartungen kennt. 



White_Fox hat gesagt.:


> und sich am Methodennamen entlangzuhangeln um damit regulär zu arbeiten...das ist doch abartig.


JavaBeans?


----------



## White_Fox (19. Feb 2019)

mihe7 hat gesagt.:


> Ich kapsle doch nicht erst etwas, um hinterher über einen "Hack" die Kapselung aufzuheben. Das ergibt einfach keinen Sinn.


Ich sehe nicht, warum das keinen Sinn ergeben sollte. Ich kapsele etwas, um den späteren Benutzer von den Innereien auszusperen. Und nicht, um den Entwickler-mich-nicht mehr an sein Werk zu lassen.

Der Zugriffsmodifizierer ist leider kein Türsteher, der ein garstiges "Du komscht hier nisch rein!" brummelt und einigen Auserwählten die Tür aufhält. Genau das will mancher halt aber manchmal. Und das hat m.E. auch nichts damit zu tun, wann man den Test und wann den Code schreibt. Die Tests schreibe ich nämlich auch zuerst. (Zugegeben, ich deklariere die Methode aber vorher und schreib auch die Javadoc vorher. Da ich ein fauler Hund bin, ist das gleichzeitig meine Testspezifikation und den Codegenerator kann ich auch nutzen.)

Ach, das wäre doch mal was...umgebungsabhängige Sichtbarkeitsmodifizierer, "testprivate" oder so. Gibt es eigentlich eine Sprache, die sowas unterstüzt?


----------



## mrBrown (19. Feb 2019)

White_Fox hat gesagt.:


> Ich sehe nicht, warum das keinen Sinn ergeben sollte. Ich kapsele etwas, um den späteren Benutzer von den Innereien auszusperen. Und nicht, um den Entwickler-mich-nicht mehr an sein Werk zu lassen.


Liegt daran, dass du einen Unterschied zwischen normalen Nutzern und Test-Code machst und an letzteres geringere Anforderungen stellst.

Eben das sollte nicht sein. Ganz im Gegenteil: Tests sind beispielhafte Nutzung und damit auch Dokumentation und sollten deshalb besonders „schön“ sein und die „richtige“ Nutzung zeigen.



White_Fox hat gesagt.:


> Und das hat m.E. auch nichts damit zu tun, wann man den Test und wann den Code schreibt. Die Tests schreibe ich nämlich auch zuerst.



Wenn man sowas wie TDD befolgt, kann man keine privaten Methoden vor deren Nutzung in echtem Code schreiben, die entstehen rein durch Refactoring.
Und wenn man nicht TDD befolgt, entstehen private Methoden auch im Idealfall durch Refactoring (oder beim Schreiben der aufrufenden Methode, was quasi ein vorgezogenes Refactoring ist), und fallen nicht vom Himmel 



White_Fox hat gesagt.:


> Ach, das wäre doch mal was...umgebungsabhängige Sichtbarkeitsmodifizierer, "testprivate" oder so. Gibt es eigentlich eine Sprache, die sowas unterstüzt?


In Java rudimentär möglich mit `@VisibleForTesting[icode] und statischer Analyse.`


----------



## mihe7 (19. Feb 2019)

@White_Fox Zum Kommentar von @mrBrown bleibt mir nur hinzuzufügen, dass ich glaube, Deine Intention zu verstehen. Korrigier mich bitte, wenn ich falsch liege.

Die Idee ist, bereits im Vorfeld zu sagen: Klasse X verwendet eine Methode m. Die ist wichtig und muss getestet werden. Gleichzeitig ist sie aber nur für Klasse X interessant und muss daher private sein. 

Ist es das, worum es Dir geht?


----------



## White_Fox (22. Feb 2019)

@mrBrown Es stimmt schon, Tests habe ich bisher immer als Teil der Entwicklung begriffen. Eine Valierung, daß die jeweilige Methode genau das tut, was in der Doku steht und sich z.B. nach einer Refaktur genauso verhält wie vorher. Da zähle ich z.B. auch Fehlerüberprüfungen dazu, d.h. ich provoziere bewußt Fehler und teste, ob die erwartete Exception kommt oder was auch immer ich als Ergebnis erwarte. Als besonders schönes Beispiel für die Benutzung würde ich sowas nicht bezeichnen, eher als wüst und ruppig. Die Tests sollen mir meine Fehler oder Schwachstellen aufzeigen. Als "Demonstration" habe ich das bisher noch nie betrachtet.

@mihe7 Im Grunde ja. Diesen Fall hatte ich bisher nur einmal (was aber nix heißen will, ich bin ja kein Programmierer ), aber genau das meine ich.


Übrigens mal ein Danke für die Diskussion hier bisher...es ist interessant mal zu lesen, wie Fachleute sowas sehen und handhaben.


----------



## mrBrown (22. Feb 2019)

White_Fox hat gesagt.:


> Es stimmt schon, Tests habe ich bisher immer als Teil der Entwicklung begriffen. Eine Valierung, daß die jeweilige Methode genau das tut, was in der Doku steht und sich z.B. nach einer Refaktur genauso verhält wie vorher.


Ja, als das nutz ich sie auch. Der Test ist aber ein ganzes Stück näher am Code, und daher entweder gleich der Doku oder genauer als diese (Fehlerhafte Tests fallen "automatisiert" auf, Fehler in der Doku brauchen Menschen) und eben funktionierender Code, anders als viele Doku - und damit gleichzeitig wunderbare Doku, zumindest für die Entwickler. ...



White_Fox hat gesagt.:


> Da zähle ich z.B. auch Fehlerüberprüfungen dazu, d.h. ich provoziere bewußt Fehler und teste, ob die erwartete Exception kommt oder was auch immer ich als Ergebnis erwarte.


... und sowas gehört ja auch in normale Doku, auch wenn es oft fehlt 



White_Fox hat gesagt.:


> Als besonders schönes Beispiel für die Benutzung würde ich sowas nicht bezeichnen, eher als wüst und ruppig.


Wenn die Aufrufe des Codes in Tests "wüst und ruppig" sind, liegt das üblicherweise daran, das auch die normale Nutzung wüst und ruppig ist 

Wenn die normale Nutzung schön ist, müssen die Tests nicht wüst und ruppig sein - wenn sie es trotzdem sind, kann das oft ein Zeichen für zwei verschiedene APIs, eine für Tests und eine "Echte", sein.

Ausnahmen gibt es natürlich immer, die meisten Ausnahmen haben aber keine wirkliche Berechtigung sondern sind eher Ausreden.



White_Fox hat gesagt.:


> Als "Demonstration" habe ich das bisher noch nie betrachtet.


Oftmals der einfachste Weg, zu sehen, wie die Funktion genau funktioniert und was sie macht - grad wenn man sich in Fremdprojekte einarbeitet oder fremde Libs nutzt.



White_Fox hat gesagt.:


> was aber nix heißen will, ich bin ja kein Programmierer


Naja - du hast ja mindestens eine private Methode und den Test dafür geschrieben -> also Programmierer 


Zu dem von @mihe7 genannten Fall: Meist sind das dann Methoden, die keinerlei private Attribute der Klasse nutzen -  dass sie also überhaupt in diese Methode gehören, kann man durchaus anzweifeln. Oft ist man da mit anderen Lösungen wie zB Strategie-Pattern besser beraten, kommt aber auf den spezifischen Fall an.


----------



## mihe7 (22. Feb 2019)

@mrBrown den Fall meinte ich noch nicht einmal  Ich meinte ein in den Entwurf vorgezogenes Refactoring.


----------

