...
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:

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 | ||
|---|---|---|
| ||
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 | ||
|---|---|---|
| ||
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.
|