Test-Code in Java-Klassen verstecken (wie mit Precompiler möglich)

Status
Nicht offen für weitere Antworten.
K

Klaus

Gast
Hi,
und zwar müssen wir Code schreiben, der sehr sehr gut getestet werden soll mit entsprechenden Testcases. Am Ende werden wir erheblich mehr Testcode als wirklichen Code haben.

Nun ist die Frage, wie man Testcode elegant in Java-Klassen einbetten kann.

Was ich damit meine:
Wir würden unsere Testfälle gerne im "JUnit-Format" schreiben (JUnit3, 4 geht leider nicht), so dass wir am Ende mit einem Klick alle Testfälle durchlaufen können. Das Problem ist nun aber ein wenig, dass unsere Klassen/Methoden relativ viel vor dem Benutzer verstecken, da ist es aber dann schwierig, diese internen Methoden zu testen.

Bevor nun der Aufschrei kommt: Es handelt sich um einen Emulator der um bestimmte Funktionalität erweitert werden soll. Deswegen sind manche Methoden von außen überhaupt nicht zugreifbar, werden aber vom emulierten Code (über teilweise mehrere Umwege) aufgerufen.


Eine Möglichkeit wäre es, nun statt einer extra Klasse für den Testfall die Testfälle innerhalb der zu testenden Klasse zu haben.

Also irgendetwas wie:
Java:
class TesteMich {
  private int zuTestendeMethode() {
  //...
  }

  //Testcases
  public void test_Testfall1() {
  //Teste zuTestendeMethode
  }
}

Würde vom Prinzip gehen, wäre aber in meinen Augen doch unschön. Zum einen würde es die Klasse umgemein aufblähen (da mehr Testcode als echter Code) und zum zweiten, wenn man ein TestMich Objekt hat, würde man die Methode test_Testfall1 (und Testfall2, 3, ...) sehen.

Nun ist meine Frage: Wie löst man das elegant?

In C/C++/C# konnte man schön auf den Precompiler zurück greifen, und dann z.B. soetwas schreiben:
Java:
class TesteMich {
  private int zuTestendeMethode() {
  //...
  }

  #ifdef TESTRUN
  //Testcases
  public void test_Testfall1() {
  //Teste zuTestendeMethode
  }
  #endif
}


Oder
Java:
class TesteMich {
#ifdef TESTRUN
  #define PRIVATEACC public
#else
  #define PRIVATEACC private
#endif
   PRIVATEACC int zuTestendeMethode() {
  //...
  }
}
So dass man mit entsprechenden Flags zwischen Testcode und Produktivcode (der kein Testcode enthält) entscheiden konnte.

Soweit ich es nun in Erfarung bringen konnte, geht das in Java leider nicht :(

Wäre wirklich dankbar, wenn mir dort jemand weiterhelfen könnte. Schön wäre es, wenn z.B. alle private/protected Methoden/Variablen für die Testcases public wären und/oder ich Code einfüge, der ein public Interface für bestimmte Methoden anbietet, wenn die Testfälle am laufen sind.

Also soetwas in der Art:
Java:
class TesteMich {
  private int zuTestendeMethode() {
  //...
  }

  #Wenn Testlauf / kein Testlauf flag gesetzt ist dann zeige folgende Methode an:
  public int test_zuTestendeMethode() {
     return zuTestendeMethode();
  }
  #endif
}

So dass dann die Testfälle an entsprechend notwendigen stellen auf test_zuTestendeMethode() anstatt auf zuTestendeMethode() zurückgreifen.


Vielen Dank für jede Hilfe.

Klaus
 

Nader

Mitglied
Precompiler gibt nicht in Java. Einiges lässt sich aber doch mit Hilfe der Java Annotation realsieren, allerdingst müsste man dann einen eigenen Compiler und IDE entwickeln, um alle deine Anforderungen zu erfüllen.:(
 

FArt

Top Contributor
Das ist m.E. nicht sinnvoll.

Ob private Methoden getestet werden müssen oder nicht, wurde bereits reichlich ausgebreitet. Wenn nötig, kann man das über Reflection erledigen. In der Regel reicht ein indirektes Testen über ihre verwendenden Methoden.
 

tfa

Top Contributor
Dieses Problem haben wir vor einiger Zeit mal diskutiert.

http://www.java-forum.org/allgemeine-java-themen/69209-unit-tests-fuer-private-methoden.html

Ich bin auch der Meinung, nur die veröffentlichte Schnittstelle der Klassen zu testen. Alles andere geschieht indirekt. Ggf. müsst du dir eben eine passende Testumgebung zurechtmocken.

[Precompiler] Soweit ich es nun in Erfarung bringen konnte, geht das in Java leider nicht
Ja, und dafür kann man nur dankbar sein.
 

skittish

Mitglied
Bevor nun der Aufschrei kommt: Es handelt sich um einen Emulator der um bestimmte Funktionalität erweitert werden soll. Deswegen sind manche Methoden von außen überhaupt nicht zugreifbar, werden aber vom emulierten Code (über teilweise mehrere Umwege) aufgerufen.
Verstehe hier das Problem nicht.
- was ist an einem Emulator so besonderes?
- wenn der Emulator Code über Umwege aufrufen kann, warum kann dies ein Unit Test nicht?

Grundsätzlich sehe ich dies so:
Protected Methoden sind so zu testen, wie sie auch vom Benutzern verwendet werden. (Kein Problem)

Über den Sinn von privaten Methoden, und dem diese testen zu wollen, mag man sich streiten. Mit JUnit wird es da auch unschön, weil JUnit für Blackbox Tests konzepiert wurde. Man testet nicht wie die Klasse arbeitet, sondern nur das die Klasse das erfüllt, was von außen gefordert ist. Und wenn sie das tut, dann ist auch sichergestellt, dass die privaten Methoden ihren Zweck erfüllen.

Damit ich jetzt nicht nur aufschreie, gebe ich hier noch das Stichwort Reflection und nested Classes. Wobei man die Wahl hat zwischen aufwändigen Testcode und Mischung von Testcodes & Produktivcode.
Im Zweifel würde ich persönlich diese Precompiler Funktionalität kurz selber schreiben. Kleines Script, welches eingebettete Klassen mit einer bestimmten Annotation (z.B. @TestingPurpose) aus dem Code entfernt.
 
K

Klaus

Gast
Hallo,
okay vielen Dank für eure Antworten.
[Precompiler] Soweit ich es nun in Erfarung bringen konnte, geht das in Java leider nicht
Ja, und dafür kann man nur dankbar sein.
Nicht wirklich. Oder man sollte zumindest bedingtes Compilieren erlauben wie es bei C# der Fall ist.


Also:
Der Emulator lädt Code, angestoßen durch Emulator.load('meinProgramm'). Intern wird dann das Programm geladen, die Befehle in dem Programm nacheinander eingelesen, dekodiert und ausgeführt. Nun gibt es einige geschütze Methoden, zum Beispiel das Speichermanagement, die essentiell zum Ausführen des Programm sind. Das heißt, das Programm führt irgendeinen Befehl aus, z.B. speichere in Adresse X folgenden Wert, dies wird vom Emulator dekodiert, die Abhandlung des Befehls wird an eine geschützte Methode weitergereicht und die ruft dann irgendwann eine private/protected Methode auf, um im virtuellen Speicher des Emulator den Wert abzulegen, wobei diese Methode noch diverse Überprüfungen, Address-Mappings etc. durchführen muss.
Alle involvierten Methoden, mit Außnahme von Emulator.load() sind protected oder private, da diese für den Entwicklung des Emulators nicht relevant sind bzw. nicht sichtbar sein sollen/dürfen.

Nun ist die Frage, wie man das testet.
Dieses mittels speziellen emulierten Programmen zu testen ist sehr schwierig bzw. fast unmöglich, da das ganze Address-Handling gegenüber dem Programm transparent geschehen soll. Sprich, das Programm sieht höchstens: Wert wurde in X gespeichert oder nicht. Ob es nun intern wirklich richtig abgespeichert wurde oder nicht ist nicht erkennbar. Insbesondere kann man so nicht auf ungültige Parameter testen, da der vorgegeben Compiler dieses meist abfängt. Später müssen die internen Methoden aber auch ungültige Parameter erkennen und abfangen. Also würde noch dazu kommen, dass man den Compiler manipuliert bzw. das ganze auf Maschinencodeebene schreibt.

Besonders schwierig wirds, wenn bestimmte Methoden nicht vom Programm direkt ausgeführt werden können, aber bei vielen anderen Befehlen involviert ist und die Testprogramme nur über solche Befehle erahnen können, ob die zugrundliegenden Funktionen auch wirklich korrekt implementiert sind. Da auch mehrere Programme gleichzeitig emuliert/ausgeführt werden sollen, ist das Funktionieren eines Befehls im Programm nur ein schlechter Indikator, ob denn alles korrekt implementiert wurde (Synchronisationsfehler usw.).


Wenn man stattdessen die Methoden in den Testfällen direkt ansprechen könnte, würde dieses vieles erheblich leichter machen und man müsste nicht den Umweg Testprogramm -> Compiler -> Methode_Zur_Befehlsabhandlung -> zuTestendeMethode gehen. Die Testfälle wären nicht nur erheblich leichter zu schreiben, sondern auch die Sicherheit, dass beim Ausführen/Emulieren von Programm nichts schief geht wäre deutlich höher.

So wie es aussieht, wird wohl (leider) Testcode mit in der Klasse landen müssen, die evt. mit der Annotation @TestingPurpose versehen werden (um behaupten zu können, dass man mit einem Precompiler es später entfernen könnte ;)). Aber wie könnte so ein Precompiler aussehen, ist das sehr schwierig zu programmieren oder kann man auf Java Funktionen zurückgreifen?
 
M

maki

Gast
Precompiler & bedingte Kompilierung sind beides Dinge die es zum Glück (oder war es Absicht? ;)) in Java nicht gibt :)

Wie man private Methoden testet steht in TFAs link, dasss das sog. "White Box" Tests sind und damit fragil, d.h. sehr anfällig für Änderungen.
Wenn das zu testende Subjekt eine einigermassen gute Struktur hat, kann man sehr leicht testen, sehe immer noch keinen Grund für einen Precompiler, bedingte Kompilierung oder gar tests in den zu testenden Klassen.

Mock Objekte sagen dir etwas? (JMOck, EasyMock, Mockito), etc. pp.)
 

skittish

Mitglied
Alle involvierten Methoden, mit Außnahme von Emulator.load() sind protected oder private, da diese für den Entwicklung des Emulators nicht relevant sind bzw. nicht sichtbar sein sollen/dürfen.
Hier sei nochmal angemerkt, dass protected garkein Problem darstellt. Eine nested Class, welche als delegate fungiert reicht aus.
Einfach gesagt, eine abgeleitete Klasse erstellen mit einer public Methode, welche nichts anderes macht als die protected Methode aufruft.

Wenn überhaupt sind private Methoden das Übel ...
 
M

maki

Gast
Hier sei nochmal angemerkt, dass protected garkein Problem darstellt. Eine nested Class, welche als delegate fungiert reicht aus.
Einfach gesagt, eine abgeleitete Klasse erstellen mit einer public Methode, welche nichts anderes macht als die protected Methode aufruft.

Wenn überhaupt sind private Methoden das Übel ...
Protected lässt sich doch einfacher testen: Einfach im selben Package die Testklasse ablegen wie die zu testende protected Methode, am besten in einem eigenen src Folder mit der gleichen package Strucktur (wie mit Maven2), dann brauchts auch kein Delegate ;)

Private zu testen ist imho der falsche Weg...
 

JanHH

Top Contributor
Wenn man unbedingt will kann man allerdings sicher auch seinen java-Code vor dem kompilieren durch einen Präprozessor jagen. C++-Compiler kann man normalerweise auch in einem "nur Präprozessor"-Modus starten, diese also quasi für java Zweckentfremden, und mit dem guten alten make in Verbindung mit gcc kann man dann sicherlich auch für java-Projekte einen build-Prozess, der mit Präprozessor arbeitet, implementieren. Ob das nun eine gute Lösung ist, ist eine andere Frage.

Oder man schreibt im Quellcode über und unter den Bereichen, wo die Testfunktionen stehen, eindeutige Identifier in Kommentare, also z.B.

// BEGIN_TEST

Testfunktionen..

// END_TEST

und schreibt sich ein kleines Program, welches automatisch in allen Quellcodedateien, die zum Projekt gehören, die Testfunktionen ein- bzw. auskommentiert. Das wäre wohl die Lösung, die ich wählen würde. So ein Programm ist ja ruckzuck geschrieben, und dann braucht es nur einen java-Aufruf per Kommandozeile, um alle Testfunktionen im Projekt zu (de-)aktivieren.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Zrebna Wieso sind eigentlich JUnit-Tests in src/test/java platziert - nur Konvention? Allgemeine Java-Themen 7
W Checkliste Unit Test Allgemeine Java-Themen 17
M Archunit Test Allgemeine Java-Themen 0
O Test schreiben mit Äquivalenzklassen (Aufgabe Prüfung) Allgemeine Java-Themen 9
B Junit Test Allgemeine Java-Themen 8
P Karate API Test läuft nicht durch . initializationError Allgemeine Java-Themen 21
J Junit surefire: enrich test information Allgemeine Java-Themen 0
Gaudimagspam White-Box-Test /Glas Box Test Allgemeine Java-Themen 2
F Junit Test + Cucumber - JSON auslesen und in einem weiteren Schritt nutzen Allgemeine Java-Themen 0
M Test geht auf Travis und mit Github Action schief aber nicht lokal Allgemeine Java-Themen 3
S Test mit Werten aus der .properties Allgemeine Java-Themen 4
T Weighted QuickUnion Test Allgemeine Java-Themen 5
S Zugriff auf jUnit Test Suite Runner-Instanzen innerhalb von Test Classes Allgemeine Java-Themen 7
S Eclipse Probleme beim Implementieren / Ausführen von jUnit 5-Test Suites Allgemeine Java-Themen 14
S Parametrisierte jUnit 5-Tests mit eigenen Datentypen/Klassen-Objekten als Test-Parameter Allgemeine Java-Themen 0
S Eclipse TestNG Default Test umbenennen Allgemeine Java-Themen 0
F UI Test auf Jenkins Allgemeine Java-Themen 1
looparda Unit Test - Abgänigkeit zur Datenbank isolieren Allgemeine Java-Themen 3
K Test-Frist Programmierung - wie vorgehen Allgemeine Java-Themen 5
E JUnit wie Testergebnisse pro Test ("Test Report") erhalten? Allgemeine Java-Themen 1
R Test Umgebung für Datenbank erstellen, was braucht es? Allgemeine Java-Themen 14
R Unit Test Allgemeine Java-Themen 1
M JUnit Test Suites Allgemeine Java-Themen 2
B Hilfe bei JUnit Test Allgemeine Java-Themen 1
E YQL Api Test - NullPointer Allgemeine Java-Themen 9
B JUnit4 Exception-Test Allgemeine Java-Themen 4
A eine test thread.join() frage Allgemeine Java-Themen 2
P Klassen Junit test funktioniert nicht... Allgemeine Java-Themen 11
W Frage zu Klassendesign und Test mit Mockito Allgemeine Java-Themen 5
G JUnit Test Methoden in anderen Thread verlagern Allgemeine Java-Themen 4
J JUnit, TestCase vs "einfacher" Test Allgemeine Java-Themen 3
1 JUnit Test Suit Allgemeine Java-Themen 2
B Test$1.class mit dem javac compiler Allgemeine Java-Themen 7
G Input/Output System.in "umbiegen" für junit-Test Allgemeine Java-Themen 4
K Unit Test consolen ein-/ausgaben. Allgemeine Java-Themen 7
DEvent Test JNI Allgemeine Java-Themen 4
S Theorie hinter Shape intersects Test..? Allgemeine Java-Themen 5
fastjack jUnit und Test von equals, hashCode, toString Allgemeine Java-Themen 11
D junit - frage zu fixtures/test suites Allgemeine Java-Themen 11
G JUnit Test Allgemeine Java-Themen 5
J GUI Test Allgemeine Java-Themen 4
G Implementierung vom AKS-Test Allgemeine Java-Themen 11
N ClassNotFound Exception bei JUnit Test? Allgemeine Java-Themen 2
GilbertGrape Warum schlägt JUnit-Test fehl? Allgemeine Java-Themen 19
K Bekomme JUnit TEst nicht zum laufen :( Allgemeine Java-Themen 9
G Ant: <test/> Allgemeine Java-Themen 2
F Kasiski-Test in BlueJ Allgemeine Java-Themen 4
H Java Multiplicoice Test (Part 2) Allgemeine Java-Themen 5
H Java Multiplicoice Test (10 Fragen) Allgemeine Java-Themen 11
F Test für Localization Allgemeine Java-Themen 6
B JUnit - Gleichen Test x-mal durchlaufen Allgemeine Java-Themen 2
H References to generic type Test.A<typ> should be param Allgemeine Java-Themen 5
N Performance-Test (Geschwindigkeit von Methoden vergleichen)? Allgemeine Java-Themen 4
S Performance Test mit JMeter Allgemeine Java-Themen 2
B httpunit test Allgemeine Java-Themen 6
S HTTPUnit Test Fehler: Error on HTTP request: 500 Internal Er Allgemeine Java-Themen 9
M Test eines Programmes Allgemeine Java-Themen 4
B Primzahlen test Allgemeine Java-Themen 3
M Unsicher, ob das Code richtig ist Allgemeine Java-Themen 4
MarvinsDepression Unbekanntes Zeichen in fremden Code wirft Fragen auf Allgemeine Java-Themen 4
schemil053 Methoden Code-Verbesserung Allgemeine Java-Themen 2
D Webarchive (war): Code verschleiern Allgemeine Java-Themen 7
D Compiler-Fehler child process exited with code 1 Allgemeine Java-Themen 1
Queenman Interface Mein Microsoft Visual Studio Code zeigt komische Dinge & Menüs an Allgemeine Java-Themen 9
A Clean Code: Variable vs. Methode Allgemeine Java-Themen 8
berserkerdq2 Versteht jemand, was diese beiden Zahlen bei dem IJVM Code zu bedeuten haben? Allgemeine Java-Themen 10
OnDemand Releaseversion Tag in Code Allgemeine Java-Themen 5
ERlK JDA Code funktioniert nicht? Allgemeine Java-Themen 4
F Code auslagern Allgemeine Java-Themen 5
D VBA Code mit Java ausführen möglich? Allgemeine Java-Themen 10
N JAVA-Code mit Grafikfenster zeichnet in Windows, aber nicht Mac. Allgemeine Java-Themen 4
JordenJost Unverständlicher Java code? Allgemeine Java-Themen 21
V Hilfe mit Java Code Allgemeine Java-Themen 4
S Processing Java Code verstehen Allgemeine Java-Themen 4
A code wird nicht ausgeführt Allgemeine Java-Themen 3
B Bitte um Code Erklärung Allgemeine Java-Themen 5
N nicht einsehbarer Fehler im code, kann nicht mehr übersetzten Allgemeine Java-Themen 51
N Regulären Ausdruck in normalen Java-Code umwandeln Allgemeine Java-Themen 12
OnDemand Clean Code oder Allgemeine Java-Themen 5
Noahscript Aus einem byte Array Steuerungszeichen und Code bekommen und ersetzen Allgemeine Java-Themen 3
J Simple Date Format Alternativen bitte um Code Allgemeine Java-Themen 14
AGW in Java-Code plötzlich ein paar Wörter in Rot Allgemeine Java-Themen 2
L Best Practice Auslagerung von Code = Performance Optimierung? Allgemeine Java-Themen 4
H Precompilierten code ansehen Allgemeine Java-Themen 3
R Wo müsste ich im Code eine Änderung vornehmen? Allgemeine Java-Themen 6
L Ausgabe von in Echtzeit ausgeführten Code Allgemeine Java-Themen 9
Drachenbauer Wie kann ich die menge an code reduzieren? Allgemeine Java-Themen 28
Thallius Warum ist dieser Code OS abhängig? Allgemeine Java-Themen 10
S Code Erklärung Allgemeine Java-Themen 21
B Pausem im Code Allgemeine Java-Themen 2
T Java-Quiz Code Fehler Allgemeine Java-Themen 10
L Eclipse Java Code ausführen Allgemeine Java-Themen 18
F Java Code ausführen direkt nach Anmelden in Windows Allgemeine Java-Themen 2
F Code in Klassen bringen Allgemeine Java-Themen 4
S Gibt es eigentlich Java Source Code Interpreter..? Allgemeine Java-Themen 13
J JUnit - Auslassen von Code Allgemeine Java-Themen 25
F Klassen Spaghetti Code Vermeidung Allgemeine Java-Themen 16
C code oder Bibliotheken für 2-Center Problem Allgemeine Java-Themen 4
J Code Page characters darstellen Allgemeine Java-Themen 12
J wie sollte man sinnvoll seinen Code aufteilen Allgemeine Java-Themen 6

Ähnliche Java Themen

Neue Themen


Oben