Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

ModelJUnit is a Java library that extends JUnit to support model-based testing.

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

The 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.*
import net.sourceforge.czt.modeljunit.coverage.*

class VendingMachineModel implements FsmModel {
    def state = 0 // 0,25,50,75,100

    void reset(boolean testing) {state = 0}

    boolean vendGuard() {state == 100}
    @Action void vend() {state = 0}

    boolean coin25Guard() {state <= 75}
    @Action void coin25() {state += 25}

    boolean coin50Guard() {state <= 50}
    @Action void coin50() {state += 50}
}

def tester = new RandomTester(new VendingMachineModel())
tester.buildGraph()
tester.addListener "verbose"
tester.generate 20

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

Code Block
none
none
done (0, coin50, 50)
done (50, coin25, 75)
done (75, coin25, 100)
done (100, vend, 0)
done Random reset(true)
done (0, coin25, 25)
done (25, coin50, 75)
done (75, coin25, 100)
done (100, vend, 0)
done (0, coin25, 25)
done (25, coin50, 75)
done (75, coin25, 100)
done (100, vend, 0)
done (0, coin50, 50)
done (50, coin50, 100)
done (100, vend, 0)
done (0, coin25, 25)
done (25, coin50, 75)
done (75, coin25, 100)
done (100, vend, 0)

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

See also: State Pattern