Squish and Functional Mockup Interfaces (FMI)

Squish and Functional Mockup Interfaces (FMI)

When testing an application that interfaces with external devices, one often doesn’t want to use an actual device. A typical testing setup in such cases would encompass a simulation tool that mocks the device(s) in a predictable and controllable way. Testing using simulated devices have a range of benefits:

  • No need for an actual device,
  • No risk of damaging the device with erroneous commands,
  • Simulation can mock rare conditions: e.g. device malfunction,
  • Simulation can provide the test environment with it’s current state,
  • Simulation can be controlled by the test environment.

There is a large number of tools available on the market that allow simulation of various devices, especially used in embedded software development. Many of those tools are capable of communicating with other tools using Functional Mockup Interfaces – FMI.

FMI Interface

Functional Mock-up Interface (FMI) is a standard describing binary interface between simulation applications. It allows sharing the simulation data and co-simulation using multiple separate tools. The upcoming version of Squish introduces support for FMI interfaces. It can import Functional Mockup Units (FMUs), control the simulation it describes and access variables that it exports.

Squish can test applications that communicate with a simulated device without any knowledge of the simulation. In such a scenario, the Squish inputs are processed by AUT, and appropriate commands are sent to the device. In reaction to that, the device changes its state and notifies the AUT. Squish can detect changes in AUT’s GUI, and confirm a valid response.

Testing without a link between Squish and simulation.

This approach has several drawbacks. Test written in this manner are in fact tests of the simulation software as much as the AUT. Any error will cause test failure, regardless where it occurred. If the interaction between AUT and the device grows in complexity, it might become difficult to reliably test the entire system.

By allowing the test script an access to the simulation, the process can be simplified. Any commands the AUT sends to the device can be verified directly. The changes in device state can be observed directly, and even triggered from the test script. This helps to reduce the test complexity: it allows to see complex interaction as a sequence of simple steps that can be verified separately.

Test including device commands and subsequent device state change.

Here is a short example of a test script that imports an FMU while running a test:

function main() {
    // Import an FMU
    var fmictx = startFMI();
    var fmu = Fmi2Import.create( '/data/deviceModel.fmu' );

    // Run the simulation in the background at real-time pace.
    fmu.runDetached( 0.01, 1 );

    // Start an AUT
    var autctx = startApplication( "/an/aut" );
    // Preform an action on the AUT
    activateItem( waitForObjectItem( ":_QMenuBar", "Device" ) );
    activateItem( waitForObjectItem( ":Device_QMenu", "Start" ) );
    // Wait for the simulation to receive a command from AUT
    setApplicationContext( fmictx );
    var isStarted = fmu.getVariable( "isStarted" );
    waitFor( function() { return isStarted.value > 0; } );

    // Modify a simulation state
    fmu.setValue( [ "isRunning" ], [ 1 ] );
    // Wait for an application to receive an update
    setApplicationContext( autctx );
    var stopButton = waitForObject( ":Stop_QPushButton" );
    waitFor( function() { return stopButton.enabled; } );
    test.compare( waitForObject( ":Status_QLabel" ).text, "Running" );

    // Terminate the simulation
    setApplicationContext( fmictx );

In the above example the test script imports an FMU exported by a simulation tool, and starts a simulation using it. It accesses two variables exported by an FMU named “isStarted” and “isRunning”. The script uses the AUT to initialize the device and queries the simulation in order to confirm that the device received appropriate command as a result. Then, the script changes the simulation state, and confirms that the AUT reacted as expected.

You might notice that every time the script switches attention between the simulation and the AUT, it preforms a context switch. This is necessary because FMUs are always imported in it’s own separate context. This is important in order to ensure there is no interference between the AUT and the FMU, and to allow importing FMUs even when the AUT runs on an FMU-incompatible platform; e.g. an embedded device.


Leave a reply

Your email address will not be published. Required fields are marked *