Wie ermittelt man alle testbaren (zu testenden) Klassen in seinem Maven-Projekt?

Zrebna

Bekanntes Mitglied
Hallo!

Die im Fokus stehende Anwendung besteht aus 18 Maven-Projekten, wobei ein Maven-Projekt davon das Test-Projekt ist, welches vorwiegend Integrationstests enthält.
Die Unit-Tests sollten ("sollten" weil bis dato kaum welche vorhanden) ganz normal in den anderen 17 (Nicht Test-)-Projekten sein, und zwar im src/test/java-Pfad.
Es geht mir nun darum, bezogen auf eine vereinfachte und limitierte Zielsetzung, erstmal nur die Anzahl aller Klassen in der Anwendung zu ermitteln, für die man eine Unit-Test-Klasse im korrespondierendem src/test/java-Pfad erstellen könnte.

Meiner Recherche nach werden Interfaces üblicherweise nicht mit Unit-Test-Klassen direkt getestet (also eine Unit-Klasse direkt für ein Interface), abstrakte Klassen
aber schon - ist das so richtig?

Falls Ja, dann bräuchte ich also
1. alle Klassen (abstakte und konkrete, aber KEINE Interfaces)
2. dürfen sich nur im src/main/java-Pfad befinden
3. dürfen sich nicht in dem einen Test-Projekt befinden.

Fragen;
1. Sind meine obigen Filterüberlegungen bzgl. was ich brauche korrekt?
2. Ich bin nun nach Recherche über so viele Möglichkeiten gestolpert, Anzahl von Klassen zu ermitteln, dass ich mir nicht sicher bin, welche Möglichkeit zuverlässig ist und in meinem Fall genau das liefert, was ich haben möchte. Daher frage ich euch, ob ihr Möglichkeiten für meinen use case kennt und empfehlen könnt.


Lg
Zrebna
 

Oneixee5

Top Contributor
Mal so gefragt:Was willst du mit diesen Informationen machen? Du hast bestimmt in deiner IDE sowas wie "Test Coverage". Also darüber gibt es meist Ansichten oder direkt eine Code Lens oder ähnliches. Ich habe aber noch nicht versucht das zu exportieren. Man sieht ja den aktuellen Stand auch immer auf dem SonarServer. Besser kann man es doch fast nicht aufbereiten.
 

mihe7

Top Contributor
Meiner Recherche nach werden Interfaces üblicherweise nicht mit Unit-Test-Klassen direkt getestet (also eine Unit-Klasse direkt für ein Interface), abstrakte Klassen
Mal ein paar Überlegungen von meiner Seite.

Die Sache hat eigentlich weniger was mit Interface und abstrakter Klasse zu tun. Voraussetzung ist schlicht, dass eine Methodendefinition existieren muss, denn was willst Du testen, wenn keine Implementierung vorhanden ist?

Jetzt kann man sich überlegen, dass der Test auf die Methode Zugriff haben muss: private Methoden scheiden damit von vornherein aus (die werden innerhalb der Klasse benutzt und sind damit Teil eines anderen Tests).

Welche Methoden kommen für einen Test überhaupt in Frage? Es muss eine Implementierung vorhanden sein, d. h. statische Methoden, default-Implementierungen in Interfaces und natürlich Instanzmethoden (definierte, nicht nur abstrakt deklarierte, versteht sich), die mindestens nicht private sind.

Damit haben wir den Kreis schon einmal eingegrenzt. Wir nähern uns weiter über die Frage, ob und wie ich sinnvoll testen kann. Bei Methoden, die sich nicht überschreiben lassen (static oder final), bietet es sich natürlich an, den Test einmalig für die Basisklasse zu schreiben. Es wird keine zweite Implementierung geben.

Doch was ist mit Methoden, die in abgleiteten Klassen (bzw. Implementierungen des Interface) überschrieben werden können? Darf sich der Test der abgeleiteten Klasse darauf verlassen, dass die Klasse die Methode der Basisklasse nicht überschreibt? Wenn man diese Frage mit "nein" beantwortet, muss der Test sowieso in den abgeleiteten Klassen ausgeführt werden. Wozu soll man dann noch in der Basisklasse testen? Umgekehrt gilt dies, wenn man die Frage mit "ja" beantwortet.

Das Dilemma, in dem man sich nun findet lässt sich relativ leicht lösen, z. B. könnte man sagen, dass man möglichst weit oben in der Hierarchie testen möchte, um Tests nicht unnötig wiederholt implementieren zu müssen. Sofern die Methoden nicht überschrieben werden, ist das ja völlig ausreichend. Gleichzeitig benötigt man ein Werkzeug, um festzustellen, ob eine Methode überschrieben aber nicht getestet wurde. Hier hilft dann eben die statische Code-Analyse. So gibt die Coverage Auskunft, ob eine abgeleitete Methode getestet wurde.
 

Zrebna

Bekanntes Mitglied
Mal so gefragt:Was willst du mit diesen Informationen machen? Du hast bestimmt in deiner IDE sowas wie "Test Coverage". Also darüber gibt es meist Ansichten oder direkt eine Code Lens oder ähnliches. Ich habe aber noch nicht versucht das zu exportieren. Man sieht ja den aktuellen Stand auch immer auf dem SonarServer. Besser kann man es doch fast nicht aufbereiten.
Also SonarServer haben wir noch nicht.

Coverage Tool wie z.B. ECLEmma zeigt mir das nicht an - zumindest kann ich da nicht so filtern, wie ich es brauche - siehe Eingangspost. Code lens gibt es nur für VS? Ich benutze als IDE Eclipse.
 

Zrebna

Bekanntes Mitglied
Mal ein paar Überlegungen von meiner Seite.

Die Sache hat eigentlich weniger was mit Interface und abstrakter Klasse zu tun. Voraussetzung ist schlicht, dass eine Methodendefinition existieren muss, denn was willst Du testen, wenn keine Implementierung vorhanden ist?

Macht Sinn, stimmt - so werden also auch nur bei abstrakten Klassen die implementierten Methoden getestet und daher eben keine IFs, weil es dort definitiv keine Implementierungen gibt (außer ggf. Default-Implementierungen, die du unten ansprichst).
Jetzt kann man sich überlegen, dass der Test auf die Methode Zugriff haben muss: private Methoden scheiden damit von vornherein aus (die werden innerhalb der Klasse benutzt und sind damit Teil eines anderen Tests).
- Interessant, das wusste ich ehrlich nicht. Also ich habe instinktiv angenommen, dass das JUnit-FW es ermöglicht auch private Methoden zu testen, wenn sie korrekt platziert sind, also:
src/main/java/packageA/ClassA -> möglich private Methoden zu testen, wenn, die Test-Klasse liegt in:
src/test/java/packageA/ClassATest

Ist aber nicht so - wieder was gelernt xD

Welche Methoden kommen für einen Test überhaupt in Frage? Es muss eine Implementierung vorhanden sein, d. h. statische Methoden, default-Implementierungen in Interfaces und natürlich Instanzmethoden (definierte, nicht nur abstrakt deklarierte, versteht sich), die mindestens nicht private sind.

Damit haben wir den Kreis schon einmal eingegrenzt. Wir nähern uns weiter über die Frage, ob und wie ich sinnvoll testen kann. Bei Methoden, die sich nicht überschreiben lassen (static oder final), bietet es sich natürlich an, den Test einmalig für die Basisklasse zu schreiben. Es wird keine zweite Implementierung geben.

Doch was ist mit Methoden, die in abgleiteten Klassen (bzw. Implementierungen des Interface) überschrieben werden können? Darf sich der Test der abgeleiteten Klasse darauf verlassen, dass die Klasse die Methode der Basisklasse nicht überschreibt? Wenn man diese Frage mit "nein" beantwortet, muss der Test sowieso in den abgeleiteten Klassen ausgeführt werden. Wozu soll man dann noch in der Basisklasse testen? Umgekehrt gilt dies, wenn man die Frage mit "ja" beantwortet.

Das Dilemma, in dem man sich nun findet lässt sich relativ leicht lösen, z. B. könnte man sagen, dass man möglichst weit oben in der Hierarchie testen möchte, um Tests nicht unnötig wiederholt implementieren zu müssen. Sofern die Methoden nicht überschrieben werden, ist das ja völlig ausreichend. Gleichzeitig benötigt man ein Werkzeug, um festzustellen, ob eine Methode überschrieben aber nicht getestet wurde. Hier hilft dann eben die statische Code-Analyse. So gibt die Coverage Auskunft, ob eine abgeleitete Methode getestet wurde.
Problem bzgl. weit oben in der Hierarchie zu testen ist, dass in dem Unternehmen, bei dem ich eine externe BA schreibe, schon ein großer Teil der Methoden der Basisklasse von den erbenden Klassen überschrieben wird, weil ein großer Teil abstrakte Methoden sind.

Also EclEmma scheint da limitiert zu sein, An statischen lokalen Codeanalyse-Tools kenne ich bis dato nur SpotBugs und SonarLint - die können das glaube ich nicht. SonarQubeServer hat das Unternehmen nicht und kommt auch erstmal nicht - also keine Chance hier.

Trotzdem sind deine Gedanken gold wert, weil ich ja auch zeigen will, warum meine Heuristiken sehr grob, nicht korrekt im wirklichem Sinne und begrenzt sind. Diese Heuristiken sollen einfach nur abschätzen, wie lange man grob brauchen würde, um eine nicht existierende Unit-Abdeckung (es werden aktuell in diesem kleinen Unternehmen keine Unit-Tests geschrieben) "aufzuholen".
Da fand ich das Vorgehen über Klassen zu gehen pragmatischer als grobe Schätzung, weil man dann bzgl. Ticketkoordination eben auch einfach "Unit-Test-Tickets" pro zu testender Klasse erstellen und verteilen/zuweisen könnte. Dass das maximal ungenau ist, weil nicht jede Klasse gleich komplex ist und auch nicht jede Klasse dieselbe Anzahl an testbaren Methoden hat (siehe deinen Input) ist klar. Und genau diese Erkenntnisse sind wertvoll und werden von mir auch dargelegt, um zu verdeutlichen, dass mein Vorgehen bzgl. Aufwandschätzung ungenau und auch nicht korrekt ist, aber nach viel Austausch irgendwie am praktikabelsten.

Denn was soll man sonst machen? Einzelne Leuten müssten recht genau analysieren und bewerten, welche Methoden man testen will und dann darauf basierend ein Ticket erstellen, was dann z.B. ansagt "teste Methode x und Klasse y und dann noch Methode u in Klasse v".
Das erscheint mir nach Rücksprache ein größerer Ticketerstellungsaufwand.
Vielleicht ist der Ticketerstellungsaufwand gar nicht so groß, wenn man die richtigen Werkzeuge und Know-how hätte? Diese ist aber aktuell in dem kleinen Unternehmen (gerade mal ca. 25-30 Festangestellte und eine "Handvoll" Entwickler) nicht gegeben.
 

KonradN

Super-Moderator
Mitarbeiter
Du willst paar Informationen haben - wozu genau? Wenn nur die Informationen alleine reichen, dann schau Dir mal die Reporting Möglichkeiten von Maven zusammen mit diversen Plugins.

JDepend Maven Plugin - Introduction (mojohaus.org)
JDepend geht dabei mehr auf Abhängigkeiten ein aber in dem Zusammenhang wird auch die Anzahl der Klassen angegeben.

JavaNCSS Maven Plugin – Introduction (mojohaus.org)
Hier wird NCSS benutzt um diverse Informationen zu ermitteln

Evtl. gibt es noch mehr - das wären erst einmal nur die, die ich von codehaus/mojo kenne. Java NCSS könnte aber zumindest einiges holen, das interessant ist.

Evtl. ist auch dashboard von codehaus/mojo interessant, das aus diversen Quellen ein Dashboard zusammen stellt.
 

mihe7

Top Contributor
Also ich habe instinktiv angenommen, dass das JUnit-FW es ermöglicht auch private Methoden zu testen, wenn sie korrekt platziert sind, also:
Wenn beide Klassen im gleichen Package liegen, dann kannst Du "package private" Methoden testen. Zugriff auf private-Methoden ist via Reflection möglich, macht aber aus genannten Gründen in der Regel wenig Sinn. JUnit hat ReflectionUtils, die den Zugriff auf private Felder/Methoden erleichtern.

schon ein großer Teil der Methoden der Basisklasse von den erbenden Klassen überschrieben wird, weil ein großer Teil abstrakte Methoden sind.
Das ist ja auch völlig okay: abstrakte Methoden zählen mangels Implementierung nicht. Du kannst eine Methode erst testen, wenn sie nicht mehr abstrakt ist.

Einzelne Leuten müssten recht genau analysieren und bewerten, welche Methoden man testen will
Naja, wir reden von Unittests: man testet in der Regel keine Getter und Setter, man testet nicht das Framework, man testet meist keine Boundaries (wie z. B. UI). Es geht darum, Verhalten zu testen.

Dass das maximal ungenau ist, weil nicht jede Klasse gleich komplex ist und auch nicht jede Klasse dieselbe Anzahl an testbaren Methoden hat (siehe deinen Input) ist klar.
Hier könnte die zyklomatische Komplexität als Metrik etwas weiterhelfen, um den Testaufwand besser einschätzen zu können. Aber das dient auch nur der Verbesserung einer Abschätzung. Code, für den die Tests hinterher geschrieben wurden, ist z. B. oft verhältnismäßig schwer zu testen. Hier können dann Tools wie Mockito helfen.
 

Zrebna

Bekanntes Mitglied
Wenn beide Klassen im gleichen Package liegen, dann kannst Du "package private" Methoden testen. Zugriff auf private-Methoden ist via Reflection möglich, macht aber aus genannten Gründen in der Regel wenig Sinn. JUnit hat ReflectionUtils, die den Zugriff auf private Felder/Methoden erleichtern.


Das ist ja auch völlig okay: abstrakte Methoden zählen mangels Implementierung nicht. Du kannst eine Methode erst testen, wenn sie nicht mehr abstrakt ist.


Naja, wir reden von Unittests: man testet in der Regel keine Getter und Setter, man testet nicht das Framework, man testet meist keine Boundaries (wie z. B. UI). Es geht darum, Verhalten zu testen.


Hier könnte die zyklomatische Komplexität als Metrik etwas weiterhelfen, um den Testaufwand besser einschätzen zu können. Aber das dient auch nur der Verbesserung einer Abschätzung.

Das finde ich interessant, nur kann ich mir drunter nichts vorstellen. Ich habe mir gerade eine Abbildung von SonarQube angesehen, wie sowas aussehen kann. Das ist ein Histogramm: Die Y-Ache entrpcicht der Anzahl der Methoden. Die x-Achse entspricht der zyklomatischen Kmplexität, die wohl u.a. besagt, wie schwierig es ist eine Methode zu testen. Diese zyklomatische Komplexität ist nun mit Werten versehen:
1 bis 10: wenig komplexe Software mit geringem Fehlerrisiko
11 bis 20: mittelmäßig komplexe Software mit bescheidenem Fehlerrisiko
21 bis 50: hohe Komplexität bei hoher (und steigender) Wahrscheinlichkeit eines Fehlers
51 und mehr: zu hohe Komplexität in einem untestbaren System mot sehr hohem Fehlerrisiko

Gibt es hier irgendwie ein Mapping? Also selbst, wenn ich das gesamte Projekt auf diese Metrik prüfen würde und dann auch so ein schönes Histogramm hätte, dann hätte ich null Ahnung, wie ich nun daraus einen konkreten Arbeitsaufwand in Zahlen (Stunden die Unit-Tests zu schreiben) ableiten könnte. Wie würde das funktionieren?


Code, für den die Tests hinterher geschrieben wurden, ist z. B. oft verhältnismäßig schwer zu testen. Hier können dann Tools wie Mockito helfen.

Das Mockito helfen kann, damit meinst du, dass "schlecht" testbare Klassen oft irgendwelche externen Abhängigkeiten brauchen, die man eben bei einem Unit-Test nicht liefert und diese dann einfach mocken kann, oder?

Hm, es scheint mir, dass es hier nicht den 100% exakten Weg gibt. Daher konkrete Frage:
Wenn du derjenige wärest, der entscheiden müsste, wie man es am besten vom Arbeitsprozess so organisiert, dass eben versäumte nicht-getestete Klassen (die testbar wären, weil implementierte Methoden, die sich für Unit-Tests eignen - also keine getters und setters) nun allmählich getestet würden, wie würdest du es innerbetrieblich organisieren?

Mir scheint es immer noch am einfachsten einfach für eine testbare Klasse jeweils ein "TODO-Test-Ticket" zu erstellen und zuzuweisen.
 

Ebi

Mitglied
Mir scheint es immer noch am einfachsten einfach für eine testbare Klasse jeweils ein "TODO-Test-Ticket" zu erstellen und zuzuweisen.
Ich würde mir die Frage stellen, wie kann ich schnell, mit angemessenen Aufwand Mehrwert erzeugen. Der Mehrwert von Tests liegt dabei (für mich) darin, dass Fehler früher auffallen und man ein Sicherheitsnetz hat für zukünftige Änderungen am Code. Ein netter Nebeneffekt von Tests ist auch, dass man gezwungen ist, seinen Code überhaupt testbar zu bauen, was in der Regel zu einfacher lesbaren und wartbaren Code führt.

Um das zu erreichen, würde ich erstmal gar nicht so sehr den Fokus auf Unit-Tests legen. Ich würde mir zu erst einmal anschauen, was so die Usecases sind und mich dann damit beschäftigen, wie ich diese automatisiert testen kann. Dabei kommt es nun stark darauf an, was für eine Art von Applikation es ist. Wäre es zum Beispiel eine Spring-Applikation, die REST-Schnittstellen nach Außen anbietet, würde ich im ersten Schritt anfangen, Blackboxtests zu bauen, die diese Schnittstellen für die Haupt-Usecases aufruft und schaut ob das Ergebnis stimmt. Dafür würde ich Tools wie Testcontainers nutzen, um eine reproduzierbare Umgebung aufzubauen oder Wiremock um andere Systeme zu simulieren. Hierbei geht es nicht darum, alle möglichen Edgecases abzudecken, sondern nur darum erstmal eine Basis zu haben.

Als nächstes würde ich mir dann anschauen, welche Testabdeckung ich damit schon erreicht habe, dabei ist das Ziel nicht, mit dieser Art von Tests eine hohe Testabdeckung zu haben, sondern zu schauen, welche Teile der Applikation noch gar nicht abgedeckt sind. Dabei können 2 verschiedene Szenarien vorliegen.

a) Der Code wurde nicht durchlaufen, weil man dazu eine komplexe Umgebung mit den richtigen Daten und richtigen Antworten von anderen Systemen simulieren muss. Hier ist der Ansatz dann, dass man Componenten-Tests baut, und deren Abhängigkeiten mit Mockito weg mockt. An der Stelle wird es auch passieren, dass man den Code umbauen muss um überhaupt richtig testen zu können, aber zum Glück hat man ja schon eine gewisse Art von Sicherheitsnetz, dass zumindest grob sicherstellt, dass man es merkt wenn was kaputt geht.

b) Code wurde nicht durchlaufen, weil es sich dabei um toten Code handelt. Es kommt immer wieder mal vor, dass durch Änderungen, Code gar nicht mehr gebraucht wird, aber trotzdem in der Codebase bleibt. Eventuell mit einem if drum, und wenn man die Bedingung weiter verfolgt, nie true ergibt. Dieser Code kann dann einfach weg.

So würde ich mich dann von Ebene zu Ebene vorarbeiten.

Betrachte die Testabdeckung als Werkzeug, das dir hilft eine wartbare Applikation zu bauen und nicht als Metrik, die erreicht werden muss.
 

LimDul

Top Contributor
Ich würde mir die Frage stellen, wie kann ich schnell, mit angemessenen Aufwand Mehrwert erzeugen. Der Mehrwert von Tests liegt dabei (für mich) darin, dass Fehler früher auffallen und man ein Sicherheitsnetz hat für zukünftige Änderungen am Code. Ein netter Nebeneffekt von Tests ist auch, dass man gezwungen ist, seinen Code überhaupt testbar zu bauen, was in der Regel zu einfacher lesbaren und wartbaren Code führt.

Um das zu erreichen, würde ich erstmal gar nicht so sehr den Fokus auf Unit-Tests legen. Ich würde mir zu erst einmal anschauen, was so die Usecases sind und mich dann damit beschäftigen, wie ich diese automatisiert testen kann. Dabei kommt es nun stark darauf an, was für eine Art von Applikation es ist. Wäre es zum Beispiel eine Spring-Applikation, die REST-Schnittstellen nach Außen anbietet, würde ich im ersten Schritt anfangen, Blackboxtests zu bauen, die diese Schnittstellen für die Haupt-Usecases aufruft und schaut ob das Ergebnis stimmt. Dafür würde ich Tools wie Testcontainers nutzen, um eine reproduzierbare Umgebung aufzubauen oder Wiremock um andere Systeme zu simulieren. Hierbei geht es nicht darum, alle möglichen Edgecases abzudecken, sondern nur darum erstmal eine Basis zu haben.

Als nächstes würde ich mir dann anschauen, welche Testabdeckung ich damit schon erreicht habe, dabei ist das Ziel nicht, mit dieser Art von Tests eine hohe Testabdeckung zu haben, sondern zu schauen, welche Teile der Applikation noch gar nicht abgedeckt sind. Dabei können 2 verschiedene Szenarien vorliegen.

a) Der Code wurde nicht durchlaufen, weil man dazu eine komplexe Umgebung mit den richtigen Daten und richtigen Antworten von anderen Systemen simulieren muss. Hier ist der Ansatz dann, dass man Componenten-Tests baut, und deren Abhängigkeiten mit Mockito weg mockt. An der Stelle wird es auch passieren, dass man den Code umbauen muss um überhaupt richtig testen zu können, aber zum Glück hat man ja schon eine gewisse Art von Sicherheitsnetz, dass zumindest grob sicherstellt, dass man es merkt wenn was kaputt geht.

b) Code wurde nicht durchlaufen, weil es sich dabei um toten Code handelt. Es kommt immer wieder mal vor, dass durch Änderungen, Code gar nicht mehr gebraucht wird, aber trotzdem in der Codebase bleibt. Eventuell mit einem if drum, und wenn man die Bedingung weiter verfolgt, nie true ergibt. Dieser Code kann dann einfach weg.

So würde ich mich dann von Ebene zu Ebene vorarbeiten.

Betrachte die Testabdeckung als Werkzeug, das dir hilft eine wartbare Applikation zu bauen und nicht als Metrik, die erreicht werden muss.
Grundsätzlich stimme ich zu. Ich würde nur eine Ergänzung zu den Unit-Tests machen.
Das beschriebene Vorgehen halte ich für mit am besten, wenn es darum geht eine bisher nicht/unzureichend getestete Anwendung zu testen. Da ist der Fokus auf "Teste die Use-Cases" optimal, weil es den schnellsten Erkenntnisgewinn bietet und die größte Sicherheit bietet, dass die Anwendung "richtig" funktioniert. Kleinteilig Unit-Tests zu ergänzen bringt wenig - insbesondere weil man in so einer Situation meist nur das Ist-Verhalten der Methoden testet und nicht das Soll-Verhalten (weil es in solchen Konstellationen selten ein Soll-Verhalten auf Methoden gibt, dass man nachprüfen kann). Und selbst wenn sich eine Methode "seltsam" oder "unintuitiv" verhält, weiß man nicht, ob andere Teile der Anwendung auf diesem Verhalten aufbauen. Sprich Unit-Tests finden hier eher selten Fehler. Sie sind eine Investition in die Zukunft und nicht schlecht - aber der direkte Impact ist geringer.

Unit-Tests - und das ist meine Ergänzung - sind sinnvoll bei neuem Code, weil sie damit auch direkt eine Dokumentation des Soll-Verhaltens sind. Sprich, wenn man so eine Anwendung weiterentwickelt, dann sollte man den Fokus darauf legen, Unit-Tests für neuen Code oder geänderten Code schreiben. Das ist einfacher - weil man eh gerade am Code dran ist - und zum anderen ist das Soll-Verhalten der Methoden/Unit klar. Das heißt, hier finde ich auch echte Fehler, wenn das Soll-Verhalten abweicht.
Das ist auch etwas, was Tools sonarqube in den teuren Lizenzen unterstützt, dass man Quality-Gates nur auf neuen/geänderten Code festlegen kann. Und so sukzessive zu einer besseren Anwendung kommt.
 

KonradN

Super-Moderator
Mitarbeiter
Ich stimme @LimDul voll zu. Ich würde es aber etwas weiter abstrahieren - auch wenn es unter dem Strich auf das Gleiche hinaus läuft:
Bei den Tests geht es immer darum, dass Anforderungen an den Code (Egal auf welcher Ebene) getestet werden. Die Anforderungen müssen also im Detail bekannt sein. Überall, so dies bekannt ist, können also entsprechende Tests geschrieben werden.

Bei bestehendem Code hat man leider sehr oft, dass Anforderungen nicht oder nicht ausreichend dokumentiert sind und da kommt es dann tatsächlich dazu, dass man zu oft keine Tests auf Methodenebene schreiben kann.

Ich sehe aber noch einen weiteren wichtigen Punkt: Legacy Code ist oft auch schlicht ohne Refactorings nicht Unit Testbar! Eine Unit greift halt auf zig andere Units zu und die will man nicht testen. Diese sind aber auch nicht einfach so zu mocken. Das ist aus meiner Sicht in der Praxis ein weiteres Problem.

Wenn man dann mit Legacy Code arbeiten muss, dann bleibt einem nur ein Vorgehen ähnlich:
  • Als erster Schritt kann man nur generell Feature Tests einführen. Unit Tests sind oft sinnvoll nicht möglich.
  • Wenn man die Features getestet hat, dann kann man Refactorings machen. Die Tests geben einem hoffentlich genug Sicherheit (Erfahrungen zeigen aber, dass man Features nicht komplett dokumentiert und damit nicht getestet hat.)
  • Und dann bekommt man auch Unit Tests. Diese sind in meinen Augen sinnvoll, denn diese dienen nicht nur dem Test sondern auch der Dokumentation. Die Features sind dort dokumentiert.

Wenn es also möglich ist, Unit Tests für Methoden zu schreiben, dann würde ich dies tun - einfach um damit die Verhaltensweise zu dokumentieren. Aber man sollte sich überlegen, diese Tests etwas zu kennzeichnen, denn es sind keine offiziellen Features die dokumentiert werden sondern nur Verhaltensweisen, die der Code aktuell zu haben scheint.

Und da würde mich direkt interessieren: Bin ich da mit meiner Sichtweise, dass Unit Tests auch als Dokumentation dienen sollten, aus eurer Sicht eher zu extrem? JavaDoc auf (Unit-) Tests? (Ich habe halt bisher eher begrenzte Erfahrung bezüglich Teams / Projekte, da ich in meinem beruflichen Werdegang wenig gewechselt habe und so eher weniger Entwickler-Teams erleben durfte ... Daher würden mich eure beruflichen Erfahrungen / eure Praxis interessieren als Erfahrungsaustausch)
 

LimDul

Top Contributor
Das stimmt, danke für die Ergäzung. Es gibt übrigens auch für Maven und Gradle Plugins, die die Testabdeckung für neuen Code messen können.
Cool, das maven Plugin kannte ich noch nicht. Hast du da zufällig noch einen Link dazu, wie man an das diff in einem maven/jenkins Build kommt? Reine Neugierde, sonst suche ich heute abend mal selber.

Ich denke da einen Jenkins Build, der einen diff auf origin/main macht und dass da nutzt.
 

LimDul

Top Contributor
Und da würde mich direkt interessieren: Bin ich da mit meiner Sichtweise, dass Unit Tests auch als Dokumentation dienen sollten, aus eurer Sicht eher zu extrem? JavaDoc auf (Unit-) Tests? (Ich habe halt bisher eher begrenzte Erfahrung bezüglich Teams / Projekte, da ich in meinem beruflichen Werdegang wenig gewechselt habe und so eher weniger Entwickler-Teams erleben durfte ... Daher würden mich eure beruflichen Erfahrungen / eure Praxis interessieren als Erfahrungsaustausch)
Teils teils, wir hatten schon Projekte, wo wir (mit extra Annotationen) Unit-Tests dokumentiert haben für Test-Reports. Ist dann aber mangels Nützlichkeit eingeschlafen.

Für mich sind Unit-Tests immer eine Dokumentation des Soll-Verhaltens. Deswegen halte ich es auch für wichtig, dass Unit-Tests lesbar & klein sind - so dass man das Soll-Verhalten auch ablesen kann. Ich schreibe tatsächlich manchmal - eher selten - Javadoc an Unit-Tests, wenn ich zwar eine Methode teste, aber dahinter eine echte, komplexe Fachlichkeit steht, wo der Setup-Code im Test umfangreich ist und nicht mehr direkt verständlich.
 

Ebi

Mitglied
Cool, das maven Plugin kannte ich noch nicht. Hast du da zufällig noch einen Link dazu, wie man an das diff in einem maven/jenkins Build kommt? Reine Neugierde, sonst suche ich heute abend mal selber.
Das weiß ich leider nicht, wir nutzten sonar dafür, haben uns aber mal das als Alternative für die Zukunft angeschaut.

Und da würde mich direkt interessieren: Bin ich da mit meiner Sichtweise, dass Unit Tests auch als Dokumentation dienen sollten, aus eurer Sicht eher zu extrem? JavaDoc auf (Unit-) Tests?
(Unit-)Test sind eine wichtige Quelle für Informationen über ein System. Ich schau mir die auch meist als erstes an um zu verstehen, was das System macht. JavaDoc halte ich aber für das falsche Werkzeug um sie zu dokumentieren, denn JavaDoc hast du nicht im Testrunner oder Build-Report stehen. Was wir meistens machen, ist die Test-Methoden sprechenden zu benennen. Das sieht dann so aus:

Java:
@Test
void should_skip_null_values() {
    var result = MyStringJoiner.join("A", null, "B");
    assertThat(result).isEqualTo("A,B");
}

Wenn man dann doch ein bisschen mehr schreiben will, dann nutzen wir DisplayName

Java:
@Test
@DisplayName("""
             This test should test, that null values are skippt,
             and the rest of the parts are joined with ","
             """)
void should_skip_null_values() {
    var result = MyStringJoiner.join("A", null, "B");
    assertThat(result).isEqualTo("A,B");
}

Diese Info taucht dann gleich auf, falls ein Test dann rot wird, und man weiß genau was Sache ist, ohne erstmal den Code anzuschauen. Auch kann das recht nützlich sein, um mit der Fachabteilung zu reden, weil diese Info ist auch für die lesbar.

Wenn einem es wichtig ist, dass die Fachabteilung auch damit arbeiten kann, dann kann man über Dinge wie Cucumber oder Fitness nachdenken. Dort schreibt man die Tests in einer Sprache die alle Beteiligten verstehen und als Entwickler baut man Glue-Code, der dafür sorgt, dass die Tests auch ausgeführt werden. Aber das ist dann ein ganz anderes Thema und ich will hier nicht zu weit abschweifen.
 

LimDul

Top Contributor
Das weiß ich leider nicht, wir nutzten sonar dafür, haben uns aber mal das als Alternative für die Zukunft angeschaut.
Mir geht es ähnlich - das wäre eine Alternative ohne Lizenzkosten für Sonar, die man mit deutlich weniger organisatorischen Aufwand einführen kann. Wo ich nicht erst ein DevOps / Infrastruktur Team beauftragen muss Dinge einzurichten und zu beschaffen :)

(Unit-)Test sind eine wichtige Quelle für Informationen über ein System. Ich schau mir die auch meist als erstes an um zu verstehen, was das System macht. JavaDoc halte ich aber für das falsche Werkzeug um sie zu dokumentieren, denn JavaDoc hast du nicht im Testrunner oder Build-Report stehen. Was wir meistens machen, ist die Test-Methoden sprechenden zu benennen. Das sieht dann so aus:
Klar, das ist für mich selbstverständlich. Es gibt halt Konstellationen wo der Platz nicht mehr reicht. Die sollten selten sein - aber dann um so wichtiger ist es die sauber zu dokumentieren.

Wenn man dann doch ein bisschen mehr schreiben will, dann nutzen wir DisplayName
Und mal wieder was neues gelernt :)
Es ist erstaunlich, wie sehr man oft auf den gewohnten Pfaden unterwegs und gar nicht weiß, was es Alternativen gibt. Ich wusste bisher gar nicht, dass es DisplayName gibt. Damit hätten wir uns das ganze Geraffel mit der eigenen Annotation im Projekt sparen können.
 

Zrebna

Bekanntes Mitglied
Nochmal hier kurz eingehakt, für alle, die sich schon mal die zyklomatische Komplexität haben ermitteln lassen. Normalerweise misst ja diese nur wieviele Pfade es innerhalb von Methoden gibt und besagt, dass pro Pfad ein Testfall geschrieben werden muss.

Gibt es Tool oder kann zum Beispiel SonarQube folgendes:
Die zyklomatische Komplexität aller Methoden einer Klasse aufsummieren, sodass übersichtlich angezeigt wird, welche zyklomatische Komplexität jede Klasse hat?

Trotzdem erscheint auch diese Metrik problematisch.
Z.b. hätte eine Methode mit einem switch-case, das 10 oder mehr Fälle hat, eine hohe zyklomatische Komplexität, auch wenn die inhaltliche Komplexität einfach ist und Testfälle schnell geschrieben sind.
Dagegen gibt es sicherlich auch Methoden, die inhaltlich sehr komplex sind und das Entwickeln von Unit-Tests einen hohen Zeitaufwand bedeutet, obwohl sie z.B. nur einen Pfad besitzen und von dieser Metrik als wenig komplex eingestuft werden würden. Sehe ich das richtig?
 

Ebi

Mitglied
Die zyklomatische Komplexität aller Methoden einer Klasse aufsummieren, sodass übersichtlich angezeigt wird, welche zyklomatische Komplexität jede Klasse hat?
Hinsichtlich der Testabdeckung wird dir das nicht so viel bringen wie du dir erhoffst. Die zyklomatische Komplexität sagt nicht sehr viel über den Aufwand was zu testen ist, aus.

Java:
public static String getGermanWeekday(Weekdays weekday) {
        switch (weekday) {
            case MONDAY:
                return "Montag";
            case TUESDAY:
                return "Dienstag";
            case WEDNESDAY:
                return "Mittwoch";
            case THURSDAY:
                return "Donnerstag";
            case FRIDAY:
                return "Freitag";
            case SATURDAY:
                return "Samstag";
            case SUNDAY:
                return "Sonntag";
        }
        return null;
    }

Der Code hat eine zykolmatische Komplexität von 7, genauso wie:

Java:
  public String getWeekdayInUserLanguage(Weekdays weekday) {
        var authentication = SecurityContextHolder.getContext().getAuthentication();
        String currentUserName = null;
        if (!(authentication instanceof AnonymousAuthenticationToken)) {
            currentUserName = authentication.getName();          
        } else {
            currentUserName = "anonymous";
        }
        var lang = "en";
       
        if(!currentUserName.equals("anonymous")) {
            var user = userService.getUserByName(currentUserName);
           
            if(user != null) {
                var langFromUser = user.getLanguage();
                if(langFromUser != null) {
                    lang = langFromUser;
                }
            }
        }
       
        if(lang.equals("de")) {
            return getGermanWeekday(weekday);
        } else {
            return getEnglishWeekday(weekday);
        }
    }

Wobei der obere Code sehr trivial zu testen ist, der untere nicht. Der untere hat eine höhere kognitive Komplexität aber das alleine ist nicht nur der Grund für den höheren Testaufwand. Im unteren Fall musst du zum Beispiel für den UserService einen Mock erstellen, und sowas wie SecurityContextHolder.getContext().getAuthentication() ist nur mit Powermock zu mocken.

Ich vermute, dass du abschätzen willst, wie hoch der Testaufwand ist, ich glaube aber, dass alleine die zykolmatische Komplexität dafür nicht genug ist. Mir fällt ehrlich gesagt auch kein guter Ansatz dazu ein, daher wäre ich sehr interessiert, wenn du deine finalen Ergebnisse teilen würdest.
 

Zrebna

Bekanntes Mitglied
Hi!

Eine Sache möchte ich noch bzgl. dem Verständnis klären, um sicherzugehen, dass ich die Semantik richtig verstehe - es geht um folgenden Abschnitt, der die Unit-Testabdeckungsziele definiert:

1.) ... mit dem langfristigen Ziel, eine Gesamtabdeckung von 80 % zu erreichen.

2.) Hierbei ist speziell vorgesehen, dass alle Unit-Tests eine Anweisungsabdeckung von 100 % und eine Zweigabdeckung von mindestens 80 % erzielen müssen.

@ 1.) Das bedeutet einfach, dass mindestens 80% der Codebasis durch Unit-Tests abgedeckt sein sollen, oder?
@ 2,) Verstehe ich es richtig, dass das NICHT bedeutet, dass
a.) 100% der Codebasis durch Unit-Tests abgedeckt sein sollen, sodass Anweisungsabdeckung gegeben ist und mind. 80% der Codebasis
durch Unit-Tests abgedeckt sein müssen, sodass Zweigabdeckung besteht - also das nicht, SONDERN
b.) , dass diese Vorgabe sich auf die Unit-Tests selber bezieht. Also dass für alle Unit-Tests gelten soll, eine Anweisungsabdeckung von 100% zu
erzielen sowie eine Zweigabdeckung von mind. 80%.

Also angenommen eine Software hätte fiktiv in der Codebasis nur 100 Methoden.
Dann wäre 1 erfüllt, wenn es für mindestens 80 Methoden einen Unit-Test gibt.

Wäre 2 auch erfüllt, wenn es nur 10 Unit-Tests gibt (also 10% Gesamtabdeckung), aber diese 10 Unit-Tests haben bzgl. ihren getesteten Methoden 100% Anweisungsabdeckung und 80% Zweigabdeckung?

Ich hoffe, dass mein Verständnisproblem klar ist :)

Kann jemand für Aufklärung sorgen?
 

mihe7

Top Contributor
Bzgl. Punkt 1 ist halt die Frage, was man als Maßstab nimmt: Code-Zeilen? Anweisungen? Methoden? Anforderungen?

Ich würde mal annehmen, dass hier gemeint ist, dass 80 % aller Anweisungen in der Codebasis durch Unit-Tests abgedeckt sein sollen. D. h. nach Ausführung aller Unit-Tests wurden 80 % aller Anweisungen, die sich in der Codebasis befinden, mindestens einmal durchlaufen.

Das ist nicht gleichbedeutend mit 80 % aller Methoden: wenn Du 8 Methoden mit insgesamt 80 Anweisungen hast und zwei Methoden mit insgesamt ebensfalls 80 Anweisungen, dann kannst Du zwar 8 Unit-Tests für die 8 der 10 Methoden schreiben und damit 80 % der Methoden testen, es werden jedoch nur 80 der 160 Anweisungen und damit 50 % aller Anweisungen abgedeckt.

Punkt 2 verstehe ich derart, dass für jeden Unit-Test gilt, dass nach seiner Ausführung 100 % der Anweisungen und 80 % aller Pfade des Prüflings wenigstens einmal durchlaufen worden sind.
 

Zrebna

Bekanntes Mitglied
Bzgl. Punkt 1 ist halt die Frage, was man als Maßstab nimmt: Code-Zeilen? Anweisungen? Methoden? Anforderungen?

Ich würde mal annehmen, dass hier gemeint ist, dass 80 % aller Anweisungen in der Codebasis durch Unit-Tests abgedeckt sein sollen. D. h. nach Ausführung aller Unit-Tests wurden 80 % aller Anweisungen, die sich in der Codebasis befinden, mindestens einmal durchlaufen.

Das ist nicht gleichbedeutend mit 80 % aller Methoden: wenn Du 8 Methoden mit insgesamt 80 Anweisungen hast und zwei Methoden mit insgesamt ebensfalls 80 Anweisungen, dann kannst Du zwar 8 Unit-Tests für die 8 der 10 Methoden schreiben und damit 80 % der Methoden testen, es werden jedoch nur 80 der 160 Anweisungen und damit 50 % aller Anweisungen abgedeckt.

Punkt 2 verstehe ich derart, dass für jeden Unit-Test gilt, dass nach seiner Ausführung 100 % der Anweisungen und 80 % aller Pfade des Prüflings wenigstens einmal durchlaufen worden sind.
Ja, denke genau so ist es - danke!

Also 1: Bezieht sich darauf, dass mind. 80% aller Anweisungen der Codebasis durchlaufen wird.
-> Ich glaube die TestCoverage im SonarQube-Dashboard (sofern man in seinem Maven-Projekt z.B. jacoco verwendet, weil das erkennt SonarQube bzw. dessen Analyse-Ergebnisse) sagt genau das aus.

Und 2 hätte ich auch so verstanden wie du - der Prüfling ist dann die getestete Klasse oder getestete Methode.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
B Gibt es eine Funktion die den Datentyp einer Variablen ermittelt? Allgemeine Java-Themen 8
_user_q Alle Kombinationen von "0000" bis "FFFF" kompakt schrieben Allgemeine Java-Themen 13
_user_q JavaFX Robot alle Unicode-Zeichen schreiben lassen können Allgemeine Java-Themen 12
S Bookmark HTML Datei einlesen, alle Links erhalten und manche editieren..? (aktuell JSoup) Allgemeine Java-Themen 4
Sachinbhatt Sind alle Methoden in Java implizit virtuell Allgemeine Java-Themen 2
Kingamadeus2000 Alle mehrfach vorkommenden Buchstaben rekursiv aus einem String entfernen. Allgemeine Java-Themen 6
Drachenbauer wie kann ich alle instanzen einer Klasse durchsehen, ohne, dass diese in einer Liste erzeugt wurden? Allgemeine Java-Themen 11
8u3631984 Generelle Log4j.xml für alle Module Allgemeine Java-Themen 5
L Farbverlauf RGB alle Farben Allgemeine Java-Themen 28
W Server-Thread schreibt nicht alle Dateien Allgemeine Java-Themen 6
S Alle Dateinamen ermitteln Allgemeine Java-Themen 22
F Wie bekommt man alle Filenamen eines Webserver Verzeichnisses Allgemeine Java-Themen 6
S Kann ich eine Methode schreiben die alle Arten von funktionalen Interfaces akzeptiert..? Allgemeine Java-Themen 21
L Operatoren Java Reflections: Alle Methoden einer Klasse aufrufen ohne Exceptions Allgemeine Java-Themen 5
MaxG. Best Practice Alle Kombinationen berechnen Allgemeine Java-Themen 3
J Best Practice Objekt an alle Klassen verteilen ( Discord Bot ) Allgemeine Java-Themen 7
C BufferedReader/BufferedWriter schreibt nicht alle Bytes Allgemeine Java-Themen 2
J Alle Unit Tests in Maven Modul Projekt ausführen Allgemeine Java-Themen 7
S Anwendung die alle Abhaengigkeiten einer Library listet..? Allgemeine Java-Themen 5
T Alle Kombinationen aus zwei Arrays Allgemeine Java-Themen 8
K Nicht alle class-Dateien im JRE? Allgemeine Java-Themen 2
I Alle logs von Logger bekommen Allgemeine Java-Themen 3
U javax.mail.Folder.list() zeigt nicht alle Ordner Allgemeine Java-Themen 5
K Classpath Alle Classen aus einem Package lesen Allgemeine Java-Themen 7
L Alle möglichen Additionen (Rekursiv) Allgemeine Java-Themen 3
KaffeeFan Methoden replace alle Buchstaben Allgemeine Java-Themen 3
S Alle Methodenaufrufe eines Threads notieren..? Allgemeine Java-Themen 7
U Koordinaten alle Pixel eines Dreiecks zeichnen ausgeben Allgemeine Java-Themen 5
Z Eclipse hängt sich alle paar Sekunden auf (Keine Rückmeldung). Allgemeine Java-Themen 4
Seikuassi Alle Escape-Sequenzen in einem String ersetzen Allgemeine Java-Themen 4
F Java Spintax: Alle Kombinationen Erzeugen Allgemeine Java-Themen 2
Sogomn Klassen Alle in eine Klasse Allgemeine Java-Themen 11
P Methoden Alle Kombinationen aus 2 Karten berechnen Allgemeine Java-Themen 2
B Threads Barrier mit wait()/notify() aber nicht alle Prozesse terminieren Allgemeine Java-Themen 2
S .jar hat nicht alle Klassen ??? Allgemeine Java-Themen 10
T Wie kann ich alle existierenden Java-Klassen anzeigen lassen? Allgemeine Java-Themen 10
M Zufälligen String generieren und alle 5 Minuten ändern Allgemeine Java-Themen 2
M RegEx alle Matches ausgeben Allgemeine Java-Themen 5
A Applet Alle Threads beim schließen des Applets beenden Allgemeine Java-Themen 8
C SwingWorker.cancle(true) tötet alle Worker Allgemeine Java-Themen 3
B Methoden Alle Methoden und Variablen aus Java-Dateien auslesen. Allgemeine Java-Themen 7
T Alle Instancen einer Klasse auflisten Allgemeine Java-Themen 13
S Programm das alle aufgerufenen Methoden ausgibt..? Allgemeine Java-Themen 6
S Alle Kombinationen aus ArrayList - Potenzmenge Allgemeine Java-Themen 7
D Alle Variablen final setzen ? Allgemeine Java-Themen 26
brunothg Alle Kombiationen von n Ziffern Allgemeine Java-Themen 2
M Erste Schritte alle xmlFiles in zugehörige pdfFiles einlesen Allgemeine Java-Themen 4
B Variablen Alle RenderingHints.Keys (KEY_*) in Array + alle RenderingHints.Keys (VALUE_*) in Object[] Allgemeine Java-Themen 8
D generische Klasse für alle Maps (nicht Collections :-)) Allgemeine Java-Themen 11
E Logger loggt nicht alle Level Allgemeine Java-Themen 2
S Aus einer Liste<Oberklasse> alle Elemente die eine bestimmte Unterklasse von Oberklasse haben filter Allgemeine Java-Themen 8
K String: alle X Zeichen Zeilenumbruch Allgemeine Java-Themen 3
F Alle Exceptions abfangen Allgemeine Java-Themen 4
nrg JS als ScriptEngine - alle Punkte ersetzen Allgemeine Java-Themen 4
A Bildschirmauflösung geändert - alle Bildschirminhalte verschoben - was tun? Allgemeine Java-Themen 7
C Alle Klassen eines Packages lesen und instanzieren? Allgemeine Java-Themen 9
B Alle Exceptions auf einmal abfangen Allgemeine Java-Themen 4
S Warum packt er nicht alle Dateien? Allgemeine Java-Themen 13
J Alle Tage eines Jahres Allgemeine Java-Themen 2
AlexSpritze Alle Domains oder FQDN von einem Server erfragen? Allgemeine Java-Themen 2
Spot84 alle kombinationen einer string arraylist Allgemeine Java-Themen 2
S Alle Elemente von zwei Listen vergleichen Allgemeine Java-Themen 10
J Konstrukt um alle Paare und Tripel einer Punkte-Menge bilden Allgemeine Java-Themen 12
B Alle möglichen Buchstabenkombinationen in einem String Allgemeine Java-Themen 7
P alle zusammanhaengenden teilgraphen Allgemeine Java-Themen 7
A alle nicht-dplikate finden Allgemeine Java-Themen 14
M Wie kann ich alle System.out Strings in ein log window umleiten? Allgemeine Java-Themen 6
E Alle unter Prozesse der beim schließen mit schließen Allgemeine Java-Themen 3
A An alle Cracks: Anwendung beenden mit ShutdownHook? Allgemeine Java-Themen 13
J Logger gibt nicht alle Level aus Allgemeine Java-Themen 3
M alle möglichen Zahlenkombinationen Allgemeine Java-Themen 5
B in welchem verzeichnis liegen alle installierten klassen? Allgemeine Java-Themen 6
hdi Für alle fleissigen Helfer! Allgemeine Java-Themen 15
N Alle Fehler ausgeben? Allgemeine Java-Themen 4
J Zweiter Prozess der alle x Sekunden etwas abfragen soll Allgemeine Java-Themen 2
O Auf alle Events reagieren Allgemeine Java-Themen 3
B J-Unit Tests. Alle Tests eines Package einsammen. Allgemeine Java-Themen 4
U alle Dateien eines Ordners innerhalb einer JAR auflisten Allgemeine Java-Themen 6
S toString() für alle Member einer Klasse. Allgemeine Java-Themen 6
G Alle möglichen Konfigurationen eines Baumes Allgemeine Java-Themen 4
C Alle Möglichen Substrings der Länge k aus String extrahieren Allgemeine Java-Themen 9
C Alle Bilder eines binären Arrays ausgeben Allgemeine Java-Themen 3
G Alle möglichen Permutationen einer Folge n Allgemeine Java-Themen 3
V Alle Klassen eines Package auflisten? Allgemeine Java-Themen 6
H JTable Löschen [Alle Zeilen aufeinmal Löschen] Allgemeine Java-Themen 6
@ RegEx: Alle Sonderzeichen ausser dem Punkt Allgemeine Java-Themen 4
G Alle Möglichen Kombinationen einer Liste Allgemeine Java-Themen 11
H Alle möglichen Hochkommata ausschließen Allgemeine Java-Themen 6
M Gibt es ein Jar - das alle Componente Automatisch anpasst? Allgemeine Java-Themen 14
K Suche alle Objekte einer bestimmten Klasse Allgemeine Java-Themen 2
N Unter Mac Os X alle laufenden Prozesse ausgeben Allgemeine Java-Themen 3
S Änderung an Proberties datei an alle User weitergeben? Allgemeine Java-Themen 7
P Observer, nicht alle updates bearbeiten Allgemeine Java-Themen 2
der JoJo [TreeSelection] wie bekomme ich alle Elemente Allgemeine Java-Themen 4
G Alle Zeichen des Alphabets ausgeben Allgemeine Java-Themen 4
G Alle Möglichkeiten n Elemente Anzuordnen. Allgemeine Java-Themen 13
0 Alle Teiler einer Zahl performant berechnen? Allgemeine Java-Themen 9
J Funktion alle Möglichkeiten berücksichtigen Allgemeine Java-Themen 5
O Warten bis alle gestarteten Threads beendet sind? Allgemeine Java-Themen 6
G HTML file Alle relativen URL in absolute URL umschreiben? Allgemeine Java-Themen 12

Ähnliche Java Themen

Neue Themen


Oben