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