Ausführbare Spezifikationen für Java

Testing mit Jnario

Dr. Sebastian Benz

In dem Beispiel deklarieren wir ein Feld car mit dem Typ Car mittels val car = new Car. In Xtend muss der Typ auf der linken Seite einer Felddeklaration nicht angegeben werden, wenn dieser mittels Typinferenz aus der Wertzuweisung auf der rechten Seite abgeleitet werden kann. In dem Beispiel stellt car eine (vereinfachte) Schnittstelle zu unserem Fahrzeug dar, über die Umgebungsparameter wie Geschwindigkeit und Gang simuliert werden können:

When I accelerate to "100" km/h
  car.accelerate(args.first.toInt)

Alle Werte, die in einer Schrittbeschreibung in Anführungszeichen geschrieben sind, sind Parameter, auf die in der Schrittimplementierung mittels der impliziten Variable args zugegriffen werden kann. So können Werte aus den Schrittbeschreibungen in der Ausführung verwendet werden. In diesem Beispiel greifen wir mittels args.first.toInt auf den ersten Parameter zu und konvertieren diesen zu einem Integer-Wert, den wir nutzen, um das Fahrzeug entsprechend zu stimulieren.

In der Implementierung des Then-Schritts überprüfen wir den erwarteten Systemzustand. Jnario bietet den Operator =>, um das erwartete Verhalten von Objekten zu beschreiben:

Then the car should indicate gear "5"
  car.proposedGear() => args.first.toInt

Im zweiten Szenario muss kaum Ausführungslogik ergänzt werden, da die Schrittdefinitionen aus dem ersten Szenario wiederverwendet werden können. Einzig die Parameterwerte werden in den Schritten variiert. So können, wenn einmal eine Menge an elementaren Schritten implementiert ist, neue Szenarien schnell umgesetzt werden. In Eclipse wird diese Featurespezifikation automatisch in einen Java JUnit Test umgewandelt, der direkt ausgeführt werden kann (Abb. 1).

Abb. 1: Ausführbare Spezifikationen mit Jnario

Die Ausführung unseres Tests schlägt fehl, da der Algorithmus zur Berechnung des vorgeschlagenen Gangs noch nicht implementiert ist. Diesen werden wir in einer eigenen Klasse GearProposal implementieren. Szenarien eignen sich allerdings nur bedingt, um einen solchen Algorithmus zu beschreiben. Deswegen bietet Jnario eine zweite Sprache zum Schreiben von Modulspezifikationen (Unit Tests) an. Eine Modulspezifikation deklariert Fakten, die eine Implementierung erfüllen muss. Ein Fakt kann ein einzelner Ausdruck mit einer Assertion sein:

describe GearShiftProposal{
  fact new GearShiftProposal().calculate(100, 4) => 5
}

Es kann aber auch eine Beschreibung ergänzt werden, wenn der Ausdruck alleine nicht aussagekräftig genug ist (Listing 3). Fakten können auch anhand des Kontexts, in dem sie gelten, strukturiert werden (Listing 4).

Listing 3

describe GearShiftProposal{
  fact "proposes higher gear if too fast for current gear"{ 
    new GearShiftProposal().calculate(100, 4) => 5
  }
}
Listing 4

describe GearShiftProposal{
  context "increasing the gear"{
    fact propsalFor(100, 4) => 5
    fact propsalFor(80, 3) => 4
  }
  context "decreasing the gear"{
    fact propsalFor(50, 5) => 4
    fact propsalFor(10, 3) => 2
  }
  def propsalFor(int speed, int gear){
    new GearShiftProposal().calculate(speed, gear)
  }
}

Eine Modulspezifikation kann Felder und Hilfsmethoden deklarieren, die verwendet werden können, um Fakten zu beschreiben. Modulspezifikationen werden ebenfalls zu normalen JUnit-Klassen kompiliert, die direkt in Eclipse ausgeführt werden können. Die Beschreibung der einzelnen Fakten wird während der Ausführung angezeigt, sodass sich eine Testausführung wie eine Spezifikation liest, die über den aktuellen Stand der Entwicklung informiert (Abb. 2).

Abb. 2: Ausführen einer Unitspezifikation in Eclipse
Geschrieben von
Dr. Sebastian Benz
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.