Unit Testing With MATLAB

mlUnit: MATLAB Unit Testing

Jump to: navigation, search


Introduction

With the concept of Extreme Programming and Test-Driven Development and its technique of automated testing a number of testing frameworks for most programming languages were developed in the last years. The concept and architecture of all these frameworks are reaching back to SUnit, a unit test framework for the Smalltalk language published by Kent Beck in 1994. Due to its simplicity, caused amongst other things by the philosophy, that tests are written in the same language as the actual program, SUnit was ported to Java in 1998, creating JUnit. Today a whole family of these frameworks exists, called the XUnit family, e.g. CppUnit for C++, PyUnit for Python or NUnit for the .NET framework.

For the MATLAB language several unit testing frameworks were developed in the last months (in alphabetical order):

MATUnit
By Timothy Wall
MUnit
By Brad Phelan
mlUnit
By Thomas Dohmke
munit
By David Legland
Unit Testing Tools
By Kit Ng

This article describes the installation, usage and techniques of MUnit and mlUnit based on a comparison between both. It has to be said, that mlUnit is developed by the author of this article, so the article can't be fully objective (but I have tried my best).

Download

MUnit

Link
http://xtargets.com/cms/Downloads/cat_view-2.html
Version
2.4
Note
MUnit requires MTemplate, so you have to download both packages.

mlUnit

Installation

MUnit

  1. Run setups:
    MTemplate
    Start mtemplate-install-v1.4.exe and install MTemplate to $HOME/mtemplate.
    MUnit
    Start munit-install-v2.4.exe and install MUnit to $HOME/munit.
  2. Add directories to MATLAB path:
    addpath('$HOME/mtemplate');
    addpath('$HOME/munit');

 

mlUnit

  1. Unzip mlunit_1.3.zip to $HOME.
  2. Add directory to MATLAB path:
    addpath('$HOME/mlunit/src');

 

Definition Of A Test Case

The definition of a test case with MUnit and mlUnit as shown in the following two example files are nearly the same. There are minor differences in the spelling of the fixture functions -- setup and set_up, teardown and tear_down -- in the creation of the object (line 3) and the invocation of the assert statement.

MUnit

File test_munit.m
function test = test_munit

test = munit_testcase;

    function setup
    end

    function teardown
    end

    function test_success
        x = 10;
        y = 10;
        
        test.assert(x == y);
    end

    function test_failure
        x = 10;
        y = 20;
        
        test.assert(x == y);
    end
end

 

mlUnit

File test_mlunit.m
function test = test_mlunit

test = load_tests_from_mfile(test_loader);

    function set_up
    end
    
    function tear_down
    end

    function test_success
        x = 10;
        y = 10;
        
        assert(x == y);
    end

    function test_failure
        x = 10;
        y = 20;
        
        assert(x == y);
    end
end

 

Running A Test Case

MUnit

Type at the MATLAB command prompt:

suite = munit_testsuite('test_munit');
r = suite.run();
r.web();

The command r.web(); opens the MATLAB web browser with the following page:

Image:Munit.png

With edit the user can open the MATLAB editor with the respective test (file and line), with run (and debug) execute the test again (in debugging mode) and with Hide Details hide as well as display the details of failed tests.

mlUnit

Option A

Type at the MATLAB command prompt:

run(text_test_runner(1, 2), test_mlunit);

The results are written to the standard output or the given file handle (the first parameter of text_test_runner):

test_mlunit/test_success(function_test_case) ... OK
test_mlunit/test_failure(function_test_case) ... FAIL

======================================================================
FAIL: test_mlunit/test_failure(function_test_case)
----------------------------------------------------------------------
Traceback (most recent call first): 
  In p:\temp\test_mlunit.m at line 22
  In p:\temp\mlunit\src\@function_test_case\run_test.m at line 11
  In p:\temp\mlunit\src\@test_case\run.m at line 32
  In p:\temp\mlunit\src\@test_suite\run.m at line 14
  In p:\temp\mlunit\src\@text_test_runner\run.m at line 14
AssertionError: no message.
----------------------------------------------------------------------
Ran 2 tests in 0.031s

FAILED (errors=0, failures=1)

Option B (new with Version 1.4)

Type at the MATLAB command prompt:

run(gui_test_runner, 'test_mlunit');

The command opens the following MATLAB figure, executes the tests and shows the result:

Image:Mlunit.png

With Show the user can open the MATLAB editor with the respective failed test (file and line of failed assertion). With Run the test case can be executed again.

Additional Features

Both testing frameworks provide additional features, which are unique to each other.

MUnit

Bookmarking a Test Suite

MUnit allows on the front page of its user interface the creation of bookmarks to test suites.

Type at the MATLAB command prompt:

munit;

The user interface of MUnit is opened:

Image:MunitGUI.png

The bottom half presents a list of bookmarks to existing test suites, each bookmark with a link edit, run and remove. To add a new test suite to the list, simply type in the name of the test suite and press add.

Defining Assertions With Anonymous Functions or Constraints

The standard way of defining an assertion to compare two values is (nearly) the same with both frameworks:

test.assert(x == y);

The assert command of MUnit furthermore accepts an anonymous function handle as the input value:

test.assert(@() x == y);

The difference lies in the test report of a failed assertion. The following figure shows the test report of the above defined test method test_failure:

Image:MunitReport1.png

Now the assert statement of the test method is changed in that way, that it uses an anonymous function:

Image:MunitReport2.png

As you can see, the test report includes much more details about the reasons of the failed test. Therefore this is now the preferred way of defining assertions with MUnit.


With prior versions the recommended way of defining assertions was the use of constraints:

c = constraint;
test.assert(c.eq(x, y));

The constraint object supports a number of operators, eg. eq, ne, and, or, isa or ask. The last one allows the definition of interactive tests, as the argument is shown in a dialog box with two buttons Yes and No. A click to No lets the test fail.

mlUnit

The Green Bar

As most popular testing frameworks the user interface of mlUnit provides a progress bar, which shows how many tests already have been executed and even more important, whether all of them were successful (green bar) or one of them failed (red bar). You can watch the progress bar in action, if you for example execute the unit tests of mlUnit itself:

addpath('$HOME/mlunit/test');
run(gui_test_runner, 'mlunit_all_tests');

Image:MlunitBar.png

Class-Based Testing

In addition to the above shown example, which defines all test methods within one .m-file, mlUnit allows also the traditional class-based definition of tests. The following steps explain the definition of the example with this:

  1. Create a folder for the class:
    mkdir('@test_mlunit_cb');
  2. Change dir to the new folder:
    cd('@test_mlunit_cb');
  3. Create an .m-file for the constructor of the class, which is inherited of test_case:
    File test_mlunit.m
    function self = test_mlunit_cb(name)
    
    tc = test_case(name);
    self = class(struct([]), 'test_mlunit_cb', tc);
  4. Create an .m-file for each test method:
    File test_success.m
    function self = test_success(self)
    
    x = 10;
    y = 10;
    
    assert(x == y);
    File test_failure.m
    function self = test_failure(self)
    
    x = 10;
    y = 20;
    
    assert(x == y);
  5. Execute the test case:
    cd('..');
    run(gui_test_runner, 'test_mlunit_cb');
    

 

Summary

This article presented two testing frameworks for MATLAB: MUnit and mlUnit. MUnit has its focus on the management of different test suites, as it provides a list of bookmarked tests and the easy (one-click) access to all executed test methods. The major disadvantage of MUnit is the lack of a progress bar. When running a test suite with a lot of tests, e.g. taking 10 minutes, only the mouse cursor is switched to the hour glass providing no information, how many tests have passed or failed.

In constrast, the focus of mlUnit lies in the definition of test cases, either within one .m-file or as a class inherited from the base test_case. Furthermore the user interface of mlUnit provides a progress bar, but the test reports are less explanatory, as the use of anonymous functions or constraints is not intended for the definition of assertions.

Comments, Questions, Bugs

If you have a question, a comment or a bug report, please send me an email. Usually I try to answer within 24 hours. Spam and other crap goes automatically to the trash bin, so please use a precise subject.

Navigation