===================
ModelJUnit tutorial
===================
.. highlight:: java

In this tutorial, we implemented the model created last time (see
:doc:`modeling-tutorial`) using ModelJUnit_. The example solution can be found on bitbucket_.

The Model
=========

First we implement the ``FsmModel`` interface to define our eFSM in ModelJUnit:

For every input in our model, we are going to write a ModelJUnit ``Action``::

  @Action
  public void myInput() {
    // Here we should update the current state...
  }

and a guard that'll tell ModelJUnit when this action is available. The guard
should be a method with the name ``<input>Guard`` and return a boolean,
e.g.::

  public boolean myInputGuard() {
    return /* true if the current state allows myInput, false otherwise */
  }

Here is the model implemented during the tutorial

.. literalinclude:: examples/MyModel.java
   :language: java

The Adapter
===========

Next we implemented the adapter that allows our model to communicate with and
take control of our SUT.

For each one of the ``@Action`` method in the model, we added a similarly named
method in the adapter class::

  class MyAdapter [
    // ...
    public void myInput() {
      // Here we execute myInput on the SUT
    }
    // ...

and, in the model, we make sure that each ``@Action`` calls the right adapter
method::

   class MyModel implements FsmModel {
    // ...
    @Action
    public void myInput() {
      // ...
      adapter.myInput();
    }

Here is the adapter created during the tutorial:

.. literalinclude:: examples/MyAdapter.java
   :language: java


Implementing reset
==================

One of the methods that you need to implement as part of the ``FsmModel``
interface is ``reset``. In this method, your model is supposed to reset itself
as well as reset the SUT to a known state.

In case your SUT only store data in the browser, you can simply close the
browser and open a new instance. But, in case your sut has a server-side data
storage (e.g. a database) you will need to reset this to a known state as well.
This might mean overriding files, clearing a mysql table or running a command.

Implementing ``getState``
=========================

The second method that the ``FsmModel`` interface requires you to implement is
``getState``. This method should return an object, often a string, which
uniquely identify the current state. Unlike what I did during the tutorial,
do not include all the state variables in the returned stat, instead it should
correspond to the *Visible States* of your model (the states in the bubbles).

Generating tests
================

Once you have implemented your model, you can use it to generate tests.
In the tutorial example, tests were generated in the main method::

    public static void main(String[] argv) {
        MyModel model = new MyModel();
        //Tester tester = new LookaheadTester(model);
        RandomTester tester = new RandomTester(model);
        //Tester tester = new AllRoundTester(model);
        //Tester tester = new GreedyTester(model);
        tester.buildGraph();
        tester.addListener(new VerboseListener());
        tester.addListener(new StopOnFailureListener());
        tester.addCoverageMetric(new TransitionCoverage());
        tester.addCoverageMetric(new StateCoverage());
        tester.addCoverageMetric(new ActionCoverage());
        tester.generate(20);
        tester.printCoverage();
    }

First, we need to instantiate your model::

  MyModel model = new MyModel();

Then, we choose the test strategy. ModelJUnit offers four different strategies:
AllRoundTester_, GreedyTester_, LookaheadTester_ and RandomTester_::

        RandomTester tester = new RandomTester(model);

Next we tell the tester to try and build the graph from the model
implementation. This will basically generate a lot of tests until ModelJUnit
thinks it has seen all the states. It'll be used later to compute the coverage
metrics. (Hint: if you want the graph building to go faster, you can write your
model so that it is possible to connect the adapter *after* you have run
``buildGraph``)::

        tester.buildGraph();

Then, we tell ModelJUnit to collect some information about the test run::

        tester.addListener(new VerboseListener());
        tester.addCoverageMetric(new TransitionCoverage());
        tester.addCoverageMetric(new StateCoverage());
        tester.addCoverageMetric(new ActionCoverage());

.. CAUTION::
   There is a bug in ModelJUnit that prevent you to get correct state coverage
   with the ``AllRoundTester``. The coverage you get is only the number of
   covered states since the last reset.

   To get around this problem, use the following code to get state coverage::

     tester.addCoverageMetric(new StateCoverage() {
         @Override
         public String getName() {
             return "Total state coverage";
         }
     });

This tells ModelJUnit to stop the test on the first failure::

        tester.addListener(new StopOnFailureListener());

Final, we generate a test sequence with a given length and print the collected
metrics::

        tester.generate(20);
        tester.printCoverage();


Usage with IntelliJ
===================

There are some quirks to using ModelJUnit in IntelliJ, one way of integrating is
found here:

* :download:`IntelliJ ModelJUnit<../files/T04-MBT-Tutorial-files.zip>`

.. _ModelJUnit: http://www.cs.waikato.ac.nz/~marku/mbt/modeljunit/
.. _bitbucket: https://bitbucket.org/modelbasedtesting/fire-mbt
.. _here: https://bitbucket.org/modelbasedtesting/modeljunit-tutorial

.. _AllRoundTester:
   _static/modeljunit2_docs/nz/ac/waikato/modeljunit/AllRoundTester.html
.. _GreedyTester:
   _static/modeljunit2_docs/nz/ac/waikato/modeljunit/GreedyTester.html
.. _LookaheadTester:
   _static/modeljunit2_docs/nz/ac/waikato/modeljunit/LookaheadTester.html
.. _RandomTester:
   _static/modeljunit2_docs/nz/ac/waikato/modeljunit/RandomTester.html