Nachdem wir im zweiten Teil einen grundlegenden Aufbau unserer Applikation erstellt haben, geht es in diesem Teil um einen Part, der in der Entwicklung einer modernen Applikation natürlich nicht zu kurz kommen darf: Testen. Durch das wunderbare Feature des kontinuierlichen Testens (continuous testing) von sbt und dem Testframework ScalaTest wird dies so einfach wie noch nie.

~ und sbt

Die interaktive sbt console stellt mit ihren unterschiedlichen Befehlen ein mächtiges Werkzeug bereit; und das nicht nur für leidenschaftliche Konsolen- Puristen. Befehle wie clean, compile, package oder test sind selbsterklärend und kommen jedem Maven-Benutzer sofort bekannt vor. Neben weiteren zahlreichenden Befehlen, die unter anderem mit help abgerufen werden können, ist in diesem Beitrag weiterhin testOnly relevant. Damit ist es möglich - im Gegensatz zu test - lediglich eine Testklasse auszuführen:

testOnly de.witi.foo.BarTest

~ - die Tilde - ist ein kleines und leicht zu übersehendes Zeichen, das allen genannten Befehlen als Prefix vorgesetzt werden kann, um sie mit einer mächtigen Funktionalität zu erweitern: Das kontinuierliche Ausführen des Befehls. Im Falle von bspw. ~test oder ~testOnly bedeutet dies, dass sbt alle relevanten Quellcode Dateien überwacht und bei jeder entsprechenden Veränderung, die Tests automatisch ausführt.

ScalaTest

Bei ScalaTest handelt es sich um das quasi Standard Testframework für die Programmiersprache Scala. Im Gegensatz zu bekannten Frameworks für Java, wie JUnit oder TestNG, unterstützt ScalaTest, Tests in unterschiedlichen Stilen. Neben Stilen, wie FunSuite - der für Entwickler gedacht ist, die in der JUnit-Welt zu Hause sind - und verschiedenen BDD-Stilen, wie FeatureSpec - für Programmierer und Nicht-Programmierer, die bspw. gemeinsam Akzeptanztests erarbeiten - existiert auch der FunSpec-Stil, den ich im Folgendem näher beschreiben möchte.

Für einen praxisnahen Test, schauen wir uns das aktuelle XBMC-JSON- API an. Wir haben bspw. ein Lied das gerade abgespielt wird und möchten wissen, an welcher aktuellen Stelle sich das Lied gerade befindet. Hierfür bietet das API die Methode Player.GetProperties an, der wir den Parameter time mitgeben und als Antwort Player.Position.Time erhalten. Also eine Zeitangabe in Stunden, Minuten und Sekunden als Integer-Wert. Tja, allerdings würde 5:0:29 als Zeitangabe natürlich relativ unschön aussehen, besser wäre da 05:00:29. Da schreiben wir für diese Formatierung doch direkt mal einen Test:

import org.scalatest.FlatSpec
class TimeSpec extends FlatSpec {
  "Formatting" should "create a beautified time representation" in {
    val hours = 5
    val minutes = 0
    val seconds = 59
    val expected = "05:00:59"
    val result = "%02d:%02d:%02d".format(hours, minutes, seconds)
    assertResult(expected)(result)
  }
}

Das Schöne an ScalaTest ist, dass eine direkte Dokumentation der Tests in der Framework-Syntax eingebaut ist, wie hier zu sehen:

"Formatting" should "create a beautified time representation" in

Formatting wird hier übrigens als ein sogenannter Tag verwendet, was als ein Merkmal zur Kategorisierung eingesetzt wird.

Der Rest des Tests ist selbsterklärend. Zum Schluss überprüfen wir lediglich mittels assertResult(expected)(result), ob das erwartete Ergebnis dem tatsächlichen entspricht.

Parallel haben wir in der sbt console ~testOnly TimeSpec eingegeben, so dass bei jeder Änderung der Klasse der Test automatisch ausgeführt wird. Das erfolgreiche Ausführen des Tests sieht in der Konsole dann wie folgt aus:

[info] TimeSpec:
[info] Formatting
[info] - should should create a beautified time representation
[info] Run completed in 90 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 1 s, completed 29.02.2014 23:59:59

Wunderbar, wir haben eine schöne Ausgabe einer aktuellen Zeitangabe! Wie jedes Test-Framework bietet auch ScalaTest natürlich viel mehr Funktionen an, als in diesem kurzen Test zu sehen ist. Sehr empfehlenswert ist hierbei der entsprechende User Guide, der verschiedene Themengebiete anspricht, wie Testkategorisierung mittels Tags, gemeinsam genutzte Objekte (fixtures), verschiedene Vergleichsoperatoren (matchers), das Arbeiten mit Mock-Klassen und vieles mehr.

Quellcode

Der hier vorgestellte Beispielcode ist wiederum bei github zu finden: sbt-scalatest

blogroll
tags