2017-12-04 4 views
0

In der Scalacheck documentation für Stateful Testing wird eine ATM-Maschine als Anwendungsfall erwähnt. Damit es funktioniert, benötigen die Befehle Parameter, zum Beispiel die PIN oder die Auszahlungsmenge. Im angegebenen Beispiel haben die Methoden in der Klasse Counter keine Parameter.Scalacheck - Parameter zu Befehlen hinzufügen

Nun meine Frage ist, wie ich eine Methode, wie dies in scalachecks Stateful-Tests testen konnte:

class Counter { 
    private var n = 0 
    def inc(i: Int) = n += i 
    ... 
} 

Die run und nextState Methoden eines Befehls einen Parameter nicht bieten. Hinzufügen eines Random.nextInt nicht funktionieren würde, weil in run und nextState der Wert würde sich unterscheiden und der Test nicht bestanden:

case object Inc extends UnitCommand { 
    def run(sut: Sut): Unit = sut.inc(Random.nextInt) 

    def nextState(state: State): State = state + Random.nextInt 
    ... 
} 

Gibt es eine Möglichkeit, einen Parameter zu dem Sut passieren?

Antwort

1

Wie Sie aus, wie genCommand feststellen können, Scalacheck Commands tut tatsächlich so etwas wie ein Kartesisches Produkt zwischen Anfangszuständen, die durch genInitialState und eine Reihe von durch genCommand erzeugten Befehle. Wenn also einige Ihrer Befehle tatsächlich einen Parameter benötigen, müssen Sie sie in Klassen von Objekten konvertieren und eine Gen für sie bereitstellen. So modifizieren Sie das Beispiel aus der Dokumentation werden Sie so etwas wie dies benötigen:

/** A generator that, given the current abstract state, should produce 
    * a suitable Command instance. */ 
def genCommand(state: State): Gen[Command] = { 
    val incGen = for (v <- arbitrary[Int]) yield Inc(v) 
    val decGen = for (v <- arbitrary[Int]) yield Dec(v) 
    Gen.oneOf(incGen, decGen, Gen.oneOf(Get, Reset)) 
} 

// A UnitCommand is a command that doesn't produce a result 
case class Inc(dif: Int) extends UnitCommand { 
    def run(sut: Sut): Unit = sut.inc(dif) 

    def nextState(state: State): State = state + dif 

    // This command has no preconditions 
    def preCondition(state: State): Boolean = true 

    // This command should always succeed (never throw an exception) 
    def postCondition(state: State, success: Boolean): Prop = success 
} 

case class Dec(dif: Int) extends UnitCommand { 
    def run(sut: Sut): Unit = sut.dec(dif) 

    def nextState(state: State): State = state - dif 

    def preCondition(state: State): Boolean = true 

    def postCondition(state: State, success: Boolean): Prop = success 
} 

Beachten Sie, wenn Sie Ihre Parameter sind nur eher Konstanten als Variablen (wie im Fall von PIN-Code ist), sollten Sie entweder hart Code Sie in den Befehlen oder machen Sie die gesamte Spezifikation Klasse statt Objekt und übergeben Sie diese Parameter von außen.

+0

Danke, das sieht nach der Lösung aus, nach der ich gesucht habe! – amuttsch

Verwandte Themen