Letztes Jahr war — zumindest gefühlt — das Jahr der Tests. Ich treibe mich hauptsächlich im Android Development Umfeld um und dort hat sich letztes Jahr wirklich viel getan. Nicht nur, dass das Thema grundsätzlich häufig aufgegriffen wurde und immer wieder Erwähnung fand. Nein, auch die Tools haben sich mächtig weiterentwickelt und greifen einem besser unter die Arme.
Trotzdem habe ich das Gefühl, dass es nicht so wirklich bei allen Entwicklern so angekommen ist. Libraries werden auf GitHub gepusht und verteilt und beinhalten meist weniger als einen Test. Selbst wenn ich dann mal welche finde, sind diese unstrukturierte und nicht ansatzweise “vollständig”.
Writing good software is hard
Grundsätzlich kann man niemanden zwingen Tests zu schreiben. Ein Tipp den ich geben kann, der bei mir auch im restlichen Leben gilt:
Tu es!
Im folgenden möchte ich drei kleine Tipps im Bereich Unit Tests geben. Man kann diese aber auch für alle anderen arten von Tests übernehmen.
Aufteilung
Jeder Test besteht mindestens aus einem Aufruf der “Implementierungs”-Methode und einer Überprüfung. Meistens gibt es auch noch ein kleines Setup, was nicht in die generelle Testklassen Setup Methode gehört, innerhalb des Tests. Wir haben also mindestens zwei maximal drei abschnitte. Mein Vorschlag, trennt die abschnitte mit einer Leerzeile. Der Rest des Testes hat keine weiteren Leerzeilen mehr.
testSaveButton_ShouldSaveFile() {
// Setup — Not required
// e.q. mocking classes, fake things, create required instances
// Test
// call the method under test
// Verify / Assert
// well, that explains all
}
Methoden Naming
Namenskonvention ist immer ein schwieriges Thema. Wer allein schon mal Pair programming durchgeführt hat, weiß wovon ich rede. Normalerweise sollten Methodennamen das beschreiben, was die Methode tut. Beispielsweise soll eine Methode, die einen Boolean speichert
saveBoolean(boolean booleanToSave)
heißen.
Bei Testmethoden ist das eigentlich genauso. Das Problem ist nur, dass eine Testmethode viel mehr macht, als eine normale “Implementierungs”-Methode (siehe dazu #Aufteilung). Wie sollen wir die Methode also nennen? Mein Vorschlag, gliedert den Namen ebenfalls in drei Kategorien:
WasTestenWir_UnterWelchenBedinungen_ErwartetesErgebnis
Auch wenn wir damit gefühlt endlos lange Namen bekommen, hilft das — vor allem weiteren Entwicklern im Projekt — unglaublich gut zu verstehen, was in dem Test passiert, warum es passiert und was man erwartet. Man erkennt sofort, nach einer neuen Implementierung die ein anderen Test breakt, warum er fehlschlägt.
Tipp: UnterWelchenBedingungen ist optional. Nicht immer ist es wichtig diesen Part zu beschreiben, da er im Test nicht gebraucht wird oder selbsterklärend ist.
Hier ein paar Beispiele
testClickPositiveButton_ShouldSaveBooleanInPreferences()testClickNegativeButton_ShouldShowAreYouSureDialog()testOpenInfo_ShouldOpenInfoActivity()testShouldShowDialog_LollipopDevice_ShouldNotShowDialog()testShouldShowDialog_PreLollipopDevice_ShouldShowDialog()
Sichtbarkeit
Mir fällt immer wieder auf, dass es einigen Entwicklern sehr schwer fällt, die Sichtbarkeit von variablen und Methoden nur für einen Test mehr zu öffnen. Kann ich verstehen. Denn laut “Regelwerk” werden private Methoden ja sowieso durch eine andere — mehr öffentliche — Methode aufgerufen. Das bedeutet, wenn ich eine öffentliche Methode teste, werden die privaten implizit mitgetestet. Soweit die Theorie. In der Praxis konnte ich das noch nie so nachvollziehen. Mein Vorschlag, scheut euch nicht variablen und Methoden mehr zu öffnen. Dabei gibt es natürlich einige Regeln zu beachten. Die Programmiersprachen haben ja nicht umsonst Sichtbarkeitsmodifier eingeführt.
- Erweitert die Sichtbarkeit nur im eigenem Projekt, welches nur von euch und eurem Team benutzt wird. Niemals in Libraries oder Source-Code, den ihr öffentlich zur Verfügung stellt.
- Identifiziert eure erweiterte Sichtbarkeit. In Java gibt es zum Beispiel die @VisibleForTesting annotation. Ansonsten gibt es auch noch Kommentare :)