Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this example, we will consider how to model and test the example from the ModelJUnit websitea simple vending machine. The system under test is illustrated by the following state diagram:

Image RemovedImage Added

The FSM VendingMachineModel class models this system. Our script makes use of the RandomTester class to generate some tests for this model. The total code looks like this:

Code Block
// require junit.jar
// require modeljunit.jar

import net.sourceforge.czt.modeljunit.Action;*
import net.sourceforge.czt.modeljunit.FsmModel;
import net.sourceforge.czt.modeljunit.RandomTester;
import net.sourceforge.czt.modeljunit.VerboseListener;
import net.sourceforge.czt.modeljunit.coverage.TransitionCoverage;coverage.*

class FSMVendingMachineModel implements FsmModel {
    def state = 0 // 0..2100

    void reset(boolean testing) {state = 0}

    boolean action0GuardvendGuard() {state == 2100}
    @Action void action0vend() {state = 0}

    boolean action1Guardcoin25Guard() {state <== 275}
    @Action void action1coin25() {state += 125}

    boolean action2Guardcoin50Guard() {state <== 050}
    @Action void action2coin50() {state += 250}

    boolean actionNoneGuard() {state != 1}

   @Action void actionNone() {}
}

def tester = new RandomTester(new FSMVendingMachineModel())
tester.buildGraph()
def trCoverage = new TransitionCoverage()
tester.addCoverageMetric(trCoverage)
tester.addListener(addListener "verbose", new VerboseListener(tester.model))
tester.generate( 20)

tester.model.printMessage(trCoverage.name + " was " + trCoverage)

When we run this script, we will see the randomly generated test transitions. The output will be:

Code Block
none
none
done (0, actionNonecoin50, 050)
done (050, action2coin25, 275)
done (275, action1coin25, 1100)
done Forced (100, vend, 0)
done Random reset(true)
done (0, action2coin25, 225)
done (225, action0coin50, 075)
done (075, action2coin25, 2100)
done (2100, action0vend, 0)
done (0, actionNonecoin25, 025)
done (025, actionNonecoin50, 075)
done (075, actionNonecoin25, 100)
done (100, vend, 0)
done (0, action2coin50, 250)
done (250, action0coin50, 0100)
done Random reset(true(100, vend, 0)
done (0, actionNonecoin25, 025)
done (025, actionNonecoin50, 075)
done (075, action2coin25, 2100)
done (2100, action0vend, 0)
done (0, action2, 2)
done Random reset(true)

We can optionally obtain additional metrics about the test:

Code Block

// ... as before to create the tester

def metrics = [
    new ActionCoverage(),
    new StateCoverage(),
    new TransitionCoverage(),
    new TransitionPairCoverage()
]
metrics.each {
    tester.addCoverageMetric it
}

tester.addListener "verbose", new VerboseListener(tester.model)
tester.generate 20

println 'Metrics Summary:'
metrics.each {
    tester.model.printMessage "$it.name was $it"
}

This generates the following:

Code Block
none
none

Metrics Summary:
Action Coverage was 3/3
State Coverage was 5/5
Transition Coverage was 4/5
7/8
Transition-Pair Coverage was 9/12

We can also add a graph listener with the following code:

Code Block

def graphListener = tester.model.getListener("graph")
graphListener.printGraphDot "vending.dot"
println "Graph contains " + graphListener.graph.numVertices() +
        " states and " + graphListener.graph.numEdges() + " transitions."

When run, a graphviz dot file is produced (corresponding to the image above) and the output is:

Code Block

Graph contains 5 states and 8 transitions.