@#$%%^&*~IAO

Robot Testing Framework

What is it?

 

RTF stands for Robot Testing Framework. It is a generic and multi-platform unit testing framework for the test driven development (TDD) which has been initially designed for the robotic systems. RTF can deal with different levels of unit testing in the real or simulated environment. The robot testing framework also provides facilities for developing and running middleware and language independent tests; thus can be used for any TDD system.

Philosophy

 

RTF implementaion follows xUnit design pattern. It provides functionalities for developing and running unit tests in a language and middleware independent manner. The test cases can be developed as independent plug-ins (i.e., using scripts such as Lua, Python, Ruby or built as DLLs using C++, ADA) to be loaded and executed by an automated test runner. A fixture manager also prepares the setup and actively monitors that all the requirements for running the tests are satisfied during the execution of the tests.

Installation

 

RTF library does not depend on any external library. The RTF framework has a test runner utility to easily run the test cases which are built as plug-ins. Test cases can be organized in test suits using simple xml files to be executed by the test runner. The build system checks for the installation of TinyXml and, in case, it cannot find any installed version of that, it uses the internal version which is delivered with the RTF.

Licensing

 

RTF is an open-source software package which has been developed under GNU Lesser General Public License (LGPL).

Simple Examples

#include <stdio.h>
#include <TestCase.h>
#include <TestResult.h>
#include <ConsoleListener.h>
#include <TestAssert.h>

using namespace RTF;

class MyTest : public TestCase {
public:
    MyTest() : TestCase("MyTest") {

    }

    virtual ~MyTest() { }

    virtual bool setup(int argc, char **argv) {
        RTF_TEST_REPORT("running MyTest::setup...");
        return true;
    }

    virtual void tearDown() {
        RTF_TEST_REPORT("running MyTest::teardown...");
        RTF_ASSERT_ERROR("this is just for example!");
    }

    virtual void run() {
        RTF_TEST_REPORT("testing integers");
        RTF_TEST_FAIL_IF(2<3, "is not smaller");
        int a = 5;
        int b = 3;
        RTF_TEST_FAIL_IF(a<b, Asserter::format("%d is not smaller than %d.", a, b));
    }

};

int main(int argc, char** argv)
{
    // create a test listener to collect the result
    // and enbale the verbose mode
    ConsoleListener listener(true);

    // create a test result and add the listeners
    TestResult result;
    result.addListener(&listener);

    // calling a test case
    MyTest atest;
    atest.TestCase::run(result);

    return 0;
}

A simple test case

#include <stdio.h>
#include <TestCase.h>
#include <TestResult.h>
#include <TestRunner.h>
#include <ConsoleListener.h>
#include <TestAssert.h>

using namespace RTF;

class MyTest : public TestCase {
public:
    MyTest() : TestCase("MyTest") {

    }

    virtual ~MyTest() { }

    virtual bool setup(int argc, char** argv) {
        RTF_TEST_REPORT("running MyTest::setup...");
        return true;
    }

    virtual void tearDown() {
        RTF_TEST_REPORT("running MyTest::teardown...");
        RTF_ASSERT_ERROR("this is just for example!");
    }

    virtual void run() {

        RTF_TEST_REPORT("testing integers");
        RTF_TEST_FAIL_IF(2<3, "is not smaller");
        RTF_TEST_FAIL_IF(5<3, "is not smaller");
    }

};

int main(int argc, char** argv)
{
    // create a test listener to collect the result
    ConsoleListener listener(false);

    // create a test result and add the listeners
    TestResult result;
    result.addListener(&listener);

    // create a test runner
    TestRunner runner;
    MyTest atest;
    runner.addTest(&atest);
    runner.run(result);

    return 0;
}

Using test runner

#include <stdio.h>
#include <TestCase.h>
#include <TestResult.h>
#include <TestRunner.h>
#include <TestSuit.h>
#include <ConsoleListener.h>
#include <TestAssert.h>
#include <TestResultCollector.h>
#include <TextOutputter.h>

using namespace RTF;

class MyTest1 : public TestCase {
public:
    MyTest1() : TestCase("MyTest1") { }

    virtual void run() {
        RTF_TEST_REPORT("testing smaller");
        RTF_TEST_FAIL_IF(3<5, "is not smaller");
    }
};

class MyTest2 : public TestCase {
public:
    MyTest2() : TestCase("MyTest2") { }

    virtual void run() {
        RTF_TEST_REPORT("testing equality");
        RTF_TEST_FAIL_IF(5==3, "are not equal");
    }
};


int main(int argc, char** argv)
{
    // create a test listener to print out the result
    ConsoleListener listener(false);

    // create a test result collector to collect the result
    TestResultCollector collector;

    // create a test result and add the listeners
    TestResult result;
    result.addListener(&listener);
    result.addListener(&collector);


    // create a test suit and the test cases
    TestSuit suit("MyTestSuit");
    MyTest1 test1;
    MyTest2 test2;
    suit.addTest(&test1);
    suit.addTest(&test2);

    // create a test runner
    TestRunner runner;    
    runner.addTest(&suit);
    runner.run(result);

    // print out some simple statistics
    printf("\n-------- results ---------\n");
    printf("Total number of tests : %d\n", collector.testCount());
    printf("Number of passed tests: %d\n", collector.passedCount());
    printf("Number of failed tests: %d\n", collector.failedCount());

    // store the results in a text file
    TextOutputter outputter(collector);
    outputter.write("./result.txt");
    return 0;
}

Using result collector

#include <stdio.h>
#include <TestCase.h>
#include <TestResult.h>
#include <TestRunner.h>
#include <TestSuit.h>
#include <ConsoleListener.h>
#include <TestAssert.h>

using namespace RTF;

class MyTest1 : public TestCase {
public:
    MyTest1() : TestCase("MyTest1") { }

    virtual void run() {
        RTF_TEST_REPORT("testing smaller");
        RTF_TEST_FAIL_IF(3<5, "is not smaller");
    }
};

class MyTest2 : public TestCase {
public:
    MyTest2() : TestCase("MyTest2") { }

    virtual void run() {
        RTF_TEST_REPORT("testing equality");
        RTF_TEST_FAIL_IF(5==3, "are not equal");
    }
};


int main(int argc, char** argv)
{
    // create a test listener to collect the result
    ConsoleListener listener(false);

    // create a test result and add the listeners
    TestResult result;
    result.addListener(&listener);

    // create a test suit and the test cases
    TestSuit suit("MyTestSuit");
    MyTest1 test1;
    MyTest2 test2;
    suit.addTest(&test1);
    suit.addTest(&test2);

    // create a test runner
    TestRunner runner;    
    runner.addTest(&suit);
    runner.run(result);

    return 0;
}

Using test suit

#include <stdio.h>
#include <TestCase.h>
#include <TestResult.h>
#include <TestRunner.h>
#include <TestSuit.h>
#include <FixtureManager.h>
#include <ConsoleListener.h>
#include <TestAssert.h>

using namespace RTF;

class MyTest1 : public TestCase {
public:
    MyTest1() : TestCase("MyTest1") { }

    virtual void run() {
        RTF_TEST_REPORT("testing smaller");
        RTF_TEST_FAIL_IF(3<5, "is not smaller");
    }
};

class MyTest2 : public TestCase {
public:
    MyTest2() : TestCase("MyTest2") { }

    virtual void run() {
        RTF_TEST_REPORT("testing equality");
        RTF_TEST_FAIL_IF(3==3, "are not equal");
    }
};

class MyFixture : public FixtureManager {
public:
    MyFixture(RTF::FixtureEvents* dispatcher)
        : FixtureManager(dispatcher) { }

    bool setup(int argc, char** argv) {
        // setup and initialize the fixture        
        // ...
        printf("Myfixture setup!\n");        
        // return true if everything is fine.
        return true;
    }


    void tearDown() {
        // uninitialize the fixture
        // ...
        printf("Myfixture tear down!\n");
        // for an example if there is any error during tear down,
        // throw an exception.
        throw FixtureException(TestMessage("MyFixture cannot tear down!"));
    }

};

int main(int argc, char** argv)
{
    // create a test listener to collect the result
    ConsoleListener listener(false);

    // create a test result and add the listeners
    TestResult result;
    result.addListener(&listener);

    // create a test suit
    TestSuit suit("MyTestSuit");

    // create a fixture manager for the test suit
    MyFixture fixture(&suit);
    suit.setFixtureManager(&fixture);

    // creates test cases and add them to the suit
    MyTest1 test1;
    MyTest2 test2;
    suit.addTest(&test1);
    suit.addTest(&test2);

    // create a test runner and run the tests
    TestRunner runner;    
    runner.addTest(&suit);
    runner.run(result);

    return 0;
}

Using fixture manager

Developing test plug-in in C++

#ifndef _MYTEST_H_
#define _MYTEST_H_
#include <TestCase.h>

class MyTest : public RTF::TestCase {
public:

    MyTest();

    virtual ~MyTest();

    virtual bool setup(int argc, char** argv);

    virtual void tearDown();

    virtual void run();
};
#endif //_MYTEST_H_

MyTest.h

#include <TestAssert.h>
#include <Plugin.h>
#include "MyTest.h"

using namespace RTF;
PREPARE_PLUGIN(MyTest)

MyTest::MyTest() : TestCase("MyTest") { }

MyTest::~MyTest() { }

bool MyTest::setup(int argc, char** argv) {
    RTF_TEST_REPORT("running MyTest::setup...");
    return true;
}

void MyTest::tearDown() {
    RTF_TEST_REPORT("running MyTest::teardown...");
    // assert an arbitray error for example.
    RTF_ASSERT_ERROR("this is just for example!");
}

void MyTest::run() {
    RTF_TEST_REPORT("testing integers");
    RTF_TEST_FAIL_IF(2<3, "is not smaller");
    int a = 5;
    int b = 3;
    RTF_TEST_FAIL_IF(a<b, Asserter::format("%d is not smaller than %d.", a, b));
}

MyTest.cpp

cmake_minimum_required(VERSION 2.8.9)

find_package(RTF)
find_package(RTF COMPONENTS DLL)

include_directories(${CMAKE_SOURCE_DIR}
                    ${RTF_INCLUDE_DIRS})

add_library(mytest MODULE MyTest.cpp MyTest.h)

CMakeList.txt

$ testrunner --verbose --test libmytest.so 
Staring test runner.
Test case MyTest started...
[INFO]  (MyTest) reports: running MyTest::setup...
[INFO]  (MyTest) reports: testing integers
[FAIL]  (MyTest) checking (a<b): 5 is not smaller than 3.
[INFO]  (MyTest) reports: running MyTest::teardown...
[ERROR] (MyTest) asserts error with exception: this is just for example!
Test case MyTest failed!
Ending test runner.

-------- results ---------
Total number of tests : 1
Number of passed tests: 0
Number of failed tests: 1

Running the test

Developing test plug-ins in Lua, Python, Ruby, ...

--
-- TestCase table is used by the lua plugin loader
-- to invoke the corresponding methods:
--
-- TestCase.setup = function(options) ... return true end
-- TestCase.run = function() ... end 
-- TestCase.tearDown = function() ... end 
--
-- The following methods are for reporting, failures or assertions: 
--
-- RTF.setName(name)             : sets the test name
-- RTF.testReport(msg)           : reports a informative message
-- RTF.testCheck(condition, msg) : reports a failure message
-- RTF.assertError(msg)          : throws an error exception with message
-- RTF.asserFail(msg)            : throws a failure exception with message
--

--
-- setup is called before the test run to setup 
-- user defined fixture
-- @return Boolean (true/false uppon success or failure)
--
TestCase.setup = function(parameter)
    RTF.setName("MyTest")
    RTF.testReport("Preparing setup...")
    return true;
end

--
-- The implementation of the test goes here
-- @return Boolean
--
TestCase.run = function()
    RTF.testReport("Checking bigger...")
    RTF.testCheck(5>3, "5 is not bigger than 3.")
    RTF.testReport("Checking smaller...")
    RTF.testCheck(5<3, "5 is not smaller than 3.")
end


--
-- tearDown is called after the test run to tear down
-- user defined fixture
--
TestCase.tearDown = function()
    RTF.testReport("Tearing down...")
end

mytest.lua

'''
 RTF module is automatically imported by the python plugin loader
 to invoke the corresponding test case methods. To develop a new 
 test case simply implement the following class; (setup and tearDown 
 methods are optional) :

 class TestCase:
     def setup(self, param):
         return True

     def run(self):

     def tearDown(self):


 The following methods are for reporting, failure or assertions: 

 RTF.setName(name)             : sets the test name (defualt is the test filename)
 RTF.testReport(msg)           : reports a informative message
 RTF.testCheck(condition, msg) : reports a failure message
 RTF.assertError(msg)          : throws an error exception with message
 RTF.asserFail(msg)            : throws a failure exception with message
'''

class TestCase:
    # setup is called before the test's run to setup 
    # the user defined fixture
    # @return Boolean (True/False uppon success or failure)
    def setup(self, param):
        RTF.testReport("Preparing setup...")
        return True
   
    # The implementation of the test goes here
    def run(self):
        RTF.testReport("Checking bigger...")
        RTF.testCheck(5>3, "5 is not bigger than 3.")
        RTF.testReport("Checking smaller...")
        RTF.testCheck(5<3, "5 is not smaller than 3.")

    # tearDown is called after the test's run to tear down
    # the user defined fixture
    def tearDown(self):
        RTF.testReport("Tearing down...")

mytest.py

# RTF module is automatically imported by the ruby plugin loader
# to invoke the corresponding test case methods. To develop a new 
# test case simply implement the following class; (setup and tearDown 
# methods are optional) :
#
# class TestCase
#     def setup(param)
#         ...
#         return true
#     end
#
#     def run ... end
#
#     def tearDown ... end
# end
#
# The following methods are for reporting, failure or assertions: 
#
# RTF::setName(name)             : sets the test name (defualt is the test filename)
# RTF::testReport(msg)           : reports a informative message
# RTF::testCheck(condition, msg) : reports a failure message
# RTF::assertError(msg)          : throws an error exception with message
# RTF::asserFail(msg)            : throws a failure exception with message
#

class TestCase
    # setup is called before the test's run to setup 
    # the user defined fixture
    # @return Boolean (True/False uppon success or failure)
    def setup(param)
        RTF::testReport("Preparing setup...")
        return true
    end

    # The implementation of the test goes here
    def run
        RTF::testReport("Checking bigger...")
        RTF::testCheck(5>3, "5 is not bigger than 3.")
        RTF::testReport("Checking smaller...")
        RTF::testCheck(5<3, "5 is not smaller than 3.")
    end

    # tearDown is called after the test's run to tear down
    # the user defined fixture
    def tearDown
        RTF::testReport("Tearing down...")
    end
end

mytest.rb

$ testrunner --verbose --test mytest.lua
Staring test runner.
Test case  started...
[INFO]  (MyTest) reports: Preparing setup...
[INFO]  (MyTest) reports: Checking bigger...
[INFO]  (MyTest) reports: Checking smaller...
[FAIL]  (MyTest) checking (false): 5 is not smaller than 3.
[INFO]  (MyTest) reports: Tearing down...
Test case MyTest failed!
Ending test runner.

-------- results ---------
Total number of tests : 1
Number of passed tests: 0
Number of failed tests: 1

Running the test

Developing test plug-ins in ADA

With RTF.TestCase;   use RTF.TestCase;

package MyTest is

    type MyTest is new TestCase with null record;

    overriding function Setup (Self : in out MyTest;
                               Parameters : String) return Boolean;
    overriding procedure TearDown (Self : in out MyTest);
    overriding procedure Run(Self : in out MyTest);

    procedure Create;
    pragma Export (C, Create, RTF.Test_Create_Symbol);

end MyTest;

MyTest.ads

with RTF; use RTF;
With RTF.Asserter;
With MyTest; use MyTest;

package body MyTest is
    
    procedure Create is 
    begin
        SetTest(new MyTest, "MyTest");
    end;

    function Setup (Self : in out MyTest;
                    Parameters : String) return Boolean is
        pragma Unreferenced (Self);
        pragma Unreferenced (Parameters);
    begin
        Asserter.TestReport("Preparing setup...");
        return True;
    end Setup;

    procedure TearDown (Self : in out MyTest) is
         pragma Unreferenced (Self);  
    begin
        Asserter.TestReport("Tearing down...");
    end;

    procedure Run (Self : in out MyTest) is
         pragma Unreferenced (Self);  
    begin
        Asserter.TestReport("Checking bigger...");
        Asserter.TestCheck(5>3, "5 is not bigger than 3.");
        Asserter.TestReport("Checking smaller...");
        Asserter.TestCheck(5<3, "5 is not smaller than 3.");
    end;

end MyTest;

MyTest.adb