Christian H. Kuhn
2016-07-07 19:19:45 UTC
Hallo Gemeinde,
Bevor hier der Löschantrag wegen Inaktivität kommt, mach ich doch lieber
nochmal Traffic :-)
Auch mein aktuelles Projekt hat mal wieder Lerneffekte, wo ich sie nicht
erwartet habe. Ziel war, Gradle kennenzulernen und in Jenkins zu
integrieren. Dazu habe ich mir ein gemischtes Java-/Android-Thema
herausgesucht, da kann ich dann auch Android Studio kennenlernen. Mit
Android 2.3.3 hatte ich im Studium mal zu tun, mal schauen, was sich
geändert hat.
Ich schreibe eine Schachuhr. Die, die es gibt, sind mehrheitlich von
geringer Kenntnis des internationalen Turnierschachs und der FIDE-Regeln
geprägt, es gibt also sogar mögliche Anwender. Grobstruktur: drei
Pakete. Ein Paket common mit der Funktionalität, ein Paket java mit der
Java-Swing-GUI, ein Paket android mit der Android-GUI. Letzteres kommt
später und soll erstmal nicht interessieren.
Die Anwendung soll eine elektronische Schachuhr darstellen. Eine
Schachuhr hat zwei Uhren, die von einer vorgegebenen Zeit abwärts laufen
und bei Erreichen der Null ein optisches Zeichen („Fallblättchen“)
geben; zwei Knöpfe, die die Uhr auf der Seite anhalten, auf der der
Knopf gedrückt wird, und die Uhr auf der anderen Seite in Gang setzen,
so dass immer nur eine Uhr läuft; einen Knopf zum Stoppen; einen Knopf
zum Zurücksetzen. Verschiedene Funktionen zum Einstellen der Uhr sind im
Menü enthalten. Zur Zeit ist nur eine Bedenkzeitperiode möglich. Erlaubt
sind klassische (Zeit pro Partie) und Fischer-Bedenkzeiten (Zeit pro
Partie, kumulativer Zeitzuschlag pro Zug). Künftige Versionen sollen
auch mehrere Bedenkzeitperioden (mit und ohne Zugzähler) und
Bronstein-Bedenkzeiten (nicht-kumulativer Zeitzuschlag pro Zug)
enthalten. Eine Light-Version erlaubt nur voreingestellte Bedenkzeiten,
eine Pro-Version erlaubt freie Wahl der Bedenkzeit und ermöglicht
Sonderfunktionen für den Schiedsrichter.
Das Paket common enthält zwei Klassen, zwei Interfaces und einen
Aufzählungstyp. QChessClock ist die Klasse für die Gesamtfunktion. Sie
implementiert das Interface QChessClockObservable (QChessClockObserver
wird von den GUI implementiert). Der Aufzählungstyp QChessClockState
wird in einer privaten Variablen benutzt, um den Zustand (läuft,
angehalten, nicht gestartet) festzuhalten. Zwei weitere private
Variablen sind vom Typ QChessTimer. Die öffentliche Schnittstelle
besteht aus Methoden, die das Drücken der Knöpfe und die Menübefehle
abbilden, und den Methoden zum Registrieren und Benachrichtigen der
Observer. Außer notifyObservers() gibt es keine öffentliche Funktion zum
Abfragen des Zustands von privaten Variablen.
QChessTimer stellt die einzelne Uhr dar. Die „öffentliche“ Schnittstelle
ist nur paketsichtbar, da ein direkter Zugriff auf die einzelnen Uhren
nur über die Hauptklasse QChessClock erfolgen soll. Verschiedene
Konstruktoren erlauben das initiale Setzen der Bedenkzeit. start() und
stop() dienen zum Starten und Anhalten der Uhr. isRunning() gibt den
Status (läuft, angehalten) an, isFlagFallen() zeigt ein gefallenes
Blättchen an. unsetFlagFallen() setzt das Fallblättchen zurück. Und
schließlich gibt getRemainingSeconds() die verbleibende Zeit in Sekunden an.
Wer den Quellcode sehen will: https://www.qno.de/gitweb/
Das Coden war jetzt tatsächlich das kleinere Problem, und Gradle ist
zwar anders als Maven, aber gut bedienbar. Probleme tauchen beim Testen
auf. Ich will ja TDD anwenden. Also erst die Tests und dann den Code
schreiben. Hat mit JUnit4 bei QChessTimer auch ganz gut funktioniert.
Bei QChessClock habe ich nicht den Schimmer einer Vorstellung, wie ich
die Klasse testen soll. Es gibt keine Getter-Funktionen, mit denen sich
was überprüfen ließe. Ich kann also testen, dass das Testobjekt nach
Konstruktor ungleich null ist, sonst nichts. Eine Änderung der
Schnittstelle nur zu Testzwecken kommt selbstverständlich nicht in
Frage. Bleibt eigentlich nur, dass die Testklasse QChessClockObserver
implementiert und auf die Benachrichtigungen des Observable wartet. Der
Weg ist gangbar, ich habe ihn aber noch in keinem Buch gefunden. Daher
vermute ich, dass es da eleganteres gibt?
In noch extremerem Umfang gilt das für die Java-GUI. Die GUI erzeugt ein
QChessClock-Objekt und registriert sich dort als Observer. Sie stellt
die erwähnten Knöpfe und Menüs bereit, die auf die öffentlichen Methoden
der Schachuhr zugreifen. Öffentliche Methoden sind außer dem Konstruktor
und actionPerformed() noch die verschiedenen update()-Funktionen, über
die das Observable seine Zustandsänderungen mitteilt. Auch hier habe ich
praktisch nichts, was ich mit JUnit testen könnte, und andere Tests der
Klasse kenne ich nicht. Auch für den Integrationstest des gesamten
Systems scheint JUnit das falsche Mittel zu sein.
In der Folge ist entsprechend die Testabdeckung, die von JaCoCo
ermittelt wird, entsprechend niedrig. Wenn andere Tests eingesetzt
werden, werden die von JaCoCo erkannt? Oder muss man Klassen dann aus
der Testabdeckungsanalyse exkludieren?
Und schließlich die alles entscheidende Frage: Kann mir das jemand hier
beantworten? Oedr denke ich zu theoretisch?
TIA
QNo
Bevor hier der Löschantrag wegen Inaktivität kommt, mach ich doch lieber
nochmal Traffic :-)
Auch mein aktuelles Projekt hat mal wieder Lerneffekte, wo ich sie nicht
erwartet habe. Ziel war, Gradle kennenzulernen und in Jenkins zu
integrieren. Dazu habe ich mir ein gemischtes Java-/Android-Thema
herausgesucht, da kann ich dann auch Android Studio kennenlernen. Mit
Android 2.3.3 hatte ich im Studium mal zu tun, mal schauen, was sich
geändert hat.
Ich schreibe eine Schachuhr. Die, die es gibt, sind mehrheitlich von
geringer Kenntnis des internationalen Turnierschachs und der FIDE-Regeln
geprägt, es gibt also sogar mögliche Anwender. Grobstruktur: drei
Pakete. Ein Paket common mit der Funktionalität, ein Paket java mit der
Java-Swing-GUI, ein Paket android mit der Android-GUI. Letzteres kommt
später und soll erstmal nicht interessieren.
Die Anwendung soll eine elektronische Schachuhr darstellen. Eine
Schachuhr hat zwei Uhren, die von einer vorgegebenen Zeit abwärts laufen
und bei Erreichen der Null ein optisches Zeichen („Fallblättchen“)
geben; zwei Knöpfe, die die Uhr auf der Seite anhalten, auf der der
Knopf gedrückt wird, und die Uhr auf der anderen Seite in Gang setzen,
so dass immer nur eine Uhr läuft; einen Knopf zum Stoppen; einen Knopf
zum Zurücksetzen. Verschiedene Funktionen zum Einstellen der Uhr sind im
Menü enthalten. Zur Zeit ist nur eine Bedenkzeitperiode möglich. Erlaubt
sind klassische (Zeit pro Partie) und Fischer-Bedenkzeiten (Zeit pro
Partie, kumulativer Zeitzuschlag pro Zug). Künftige Versionen sollen
auch mehrere Bedenkzeitperioden (mit und ohne Zugzähler) und
Bronstein-Bedenkzeiten (nicht-kumulativer Zeitzuschlag pro Zug)
enthalten. Eine Light-Version erlaubt nur voreingestellte Bedenkzeiten,
eine Pro-Version erlaubt freie Wahl der Bedenkzeit und ermöglicht
Sonderfunktionen für den Schiedsrichter.
Das Paket common enthält zwei Klassen, zwei Interfaces und einen
Aufzählungstyp. QChessClock ist die Klasse für die Gesamtfunktion. Sie
implementiert das Interface QChessClockObservable (QChessClockObserver
wird von den GUI implementiert). Der Aufzählungstyp QChessClockState
wird in einer privaten Variablen benutzt, um den Zustand (läuft,
angehalten, nicht gestartet) festzuhalten. Zwei weitere private
Variablen sind vom Typ QChessTimer. Die öffentliche Schnittstelle
besteht aus Methoden, die das Drücken der Knöpfe und die Menübefehle
abbilden, und den Methoden zum Registrieren und Benachrichtigen der
Observer. Außer notifyObservers() gibt es keine öffentliche Funktion zum
Abfragen des Zustands von privaten Variablen.
QChessTimer stellt die einzelne Uhr dar. Die „öffentliche“ Schnittstelle
ist nur paketsichtbar, da ein direkter Zugriff auf die einzelnen Uhren
nur über die Hauptklasse QChessClock erfolgen soll. Verschiedene
Konstruktoren erlauben das initiale Setzen der Bedenkzeit. start() und
stop() dienen zum Starten und Anhalten der Uhr. isRunning() gibt den
Status (läuft, angehalten) an, isFlagFallen() zeigt ein gefallenes
Blättchen an. unsetFlagFallen() setzt das Fallblättchen zurück. Und
schließlich gibt getRemainingSeconds() die verbleibende Zeit in Sekunden an.
Wer den Quellcode sehen will: https://www.qno.de/gitweb/
Das Coden war jetzt tatsächlich das kleinere Problem, und Gradle ist
zwar anders als Maven, aber gut bedienbar. Probleme tauchen beim Testen
auf. Ich will ja TDD anwenden. Also erst die Tests und dann den Code
schreiben. Hat mit JUnit4 bei QChessTimer auch ganz gut funktioniert.
Bei QChessClock habe ich nicht den Schimmer einer Vorstellung, wie ich
die Klasse testen soll. Es gibt keine Getter-Funktionen, mit denen sich
was überprüfen ließe. Ich kann also testen, dass das Testobjekt nach
Konstruktor ungleich null ist, sonst nichts. Eine Änderung der
Schnittstelle nur zu Testzwecken kommt selbstverständlich nicht in
Frage. Bleibt eigentlich nur, dass die Testklasse QChessClockObserver
implementiert und auf die Benachrichtigungen des Observable wartet. Der
Weg ist gangbar, ich habe ihn aber noch in keinem Buch gefunden. Daher
vermute ich, dass es da eleganteres gibt?
In noch extremerem Umfang gilt das für die Java-GUI. Die GUI erzeugt ein
QChessClock-Objekt und registriert sich dort als Observer. Sie stellt
die erwähnten Knöpfe und Menüs bereit, die auf die öffentlichen Methoden
der Schachuhr zugreifen. Öffentliche Methoden sind außer dem Konstruktor
und actionPerformed() noch die verschiedenen update()-Funktionen, über
die das Observable seine Zustandsänderungen mitteilt. Auch hier habe ich
praktisch nichts, was ich mit JUnit testen könnte, und andere Tests der
Klasse kenne ich nicht. Auch für den Integrationstest des gesamten
Systems scheint JUnit das falsche Mittel zu sein.
In der Folge ist entsprechend die Testabdeckung, die von JaCoCo
ermittelt wird, entsprechend niedrig. Wenn andere Tests eingesetzt
werden, werden die von JaCoCo erkannt? Oder muss man Klassen dann aus
der Testabdeckungsanalyse exkludieren?
Und schließlich die alles entscheidende Frage: Kann mir das jemand hier
beantworten? Oedr denke ich zu theoretisch?
TIA
QNo