Overview:
Motivation
Boost.Test is a proven open source testing library which provides a robust runtime framework. With Boost.Test you can organize your test cases within suites and select the test cases or suites to execute from the command line. Many more command line options and other possibilities are available.
The TestToolBox (TTB) is a collection of test orientated classes which can run on their own but which can also be used together with Boost. By adding TTB to a Boost.Test application you can get the following possibilities:
- generation of a detailed test protocol (may be a starting point for error analysis, e.g. for tests failed during last nightly build)
- comfortably collecting of TestEvents possibly generated from several objects of your test environment, possibly originating from different threads
- automatic check of recorded events, allowing random order of events where needed
- synchronization within multithreaded environments: synchronize your test script (usually running within your main thread) with worker threads of test environment and test object
- support for automated checking of XML data (e.g. possibility to ignore uninteresting nodes and attributes, check double values with given precision, select subnodes with XPath)
- more features ...
The following chapters describe how you can add TTB functionality to a Boost.Test application and what are the necessary steps to setup a project.
Structure of a typical test project
A typical test project consists at least of the following parts:
- project settings:
contains library path definitions and preprocessor defines to configure code generation
- MyTestApp.cpp:
main source file containing
- instructions to parametrize, include and link boost library and TestToolBox,
- a "global fixture" containing initialization / cleanup routines to be executed before / after execution of the set of all test cases, furthermore here the connection to TestToolBox is established
- TestCasesA.cpp, TestCasesB.cpp,... :
- multiple files containing specific test cases possibly organized within test suites
- optional "test suite fixtures" with initialization / cleanup routines executed before / after the execution of each test case within the fixture
Required project settings
- C/C++ settings
- General / Additional Include Directories: c:/boost/boost_actual;
- Preprocessor Definitions
- TTB_USE_BOOST_TEST:
TestToolBox will activate code to support Boost test framework
- TTB_NOT_INLINE:
prepare source code to be directly included via TestToolBoxImpl.h within a single source file of your test project
- TTB_USE_STANDARD_ERROR:
activate default error format to store catched and returned errors
- TTB_USE_PUGI_XML:
optional switch, needed to add support for checking XML data with pugi xml; assumption: you have already added pugixml lib to your project.
- TRACE_IS_ON:
optional switch to activate trace output from TestToolBox sources
- Linker
- General / Additional Library Directories: c:/boost/boost_actual/lib;
Main source file MyTestApp.cpp
Connect with Boost.Test library:
#define BOOST_TEST_MODULE "Testing XmlCheck with PugiXml"
#include <boost/bind.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
Connect with implementation of TestToolBox:
#include "TestToolBox\TestToolBoxImpl.h"
TTB_TRC_DEF_GLOBALS("TestXmlCheckWithPugiXmlc", TL_VAL_DEBUG);
namespace TTB = TestToolBox;
Define your global test fixture (typical example):
struct MyGlobalSettingsForTestToolBox : public TTB::DefaultSettingsForBoostAndTTB
{
MyGlobalSettingsForTestToolBox(void)
{
std::string prefixForTestEventsWithinOutFile =
TTB::TheEnvironment()->GetCommandLineOption("-prefixEvents");
bool detailedLog = true;
TTB::TestEvents::Get()->SetDetailedLog(
detailedLog, prefixForTestEventsWithinOutFile);
InitialPreparation();
}
};
Install global fixture:
BOOST_GLOBAL_FIXTURE(MyGlobalSettingsForTestToolBox);
For a complete example see C++ Example for main source file
Test case file TestCaseX.cpp
Includes needed to use both Boost and TTB functionality:
#include <TestToolBox\TestToolBox.h>
namespace TTB = TestToolBox;
Define your test suite fixture as needed:
class MyTestSuiteFixture
{
public:
MyTestSuiteFixture()
{
TTB_INFO("\nMyTestSuiteFixture-Constructor");
}
~MyTestSuiteFixture()
{
TTB_INFO("\nMyTestSuiteFixture-Destructor");
TTB::TheXmlCheck()->SetDefaults();
}
};
Define your test cases:
BOOST_FIXTURE_TEST_SUITE(SuiteTestingSomeSubject, MyTestSuiteFixture)
TTB_BOOST_TEST_CASE(DemoTestCase)
{
int a = 4;
int b = 2;
BOOST_CHECK(a == 2 * b);
TTB_CHECK_EQUAL(a, 2 * b);
TTB_ACT_S("a=" << a << ", b=" << b);
TTB_EXP("a=4, b=2");
}};
BOOST_AUTO_TEST_SUITE_END()
For a complete example see C++ Example for test case source file
Command line params to control runtime behaviour
Both Boost Test and TestToolBox can be controlled via command line params. Because of a slightly differing syntax you can mix params for both tools. Each tool will only take into account those params matching with the expected syntax. All params with other syntax will be ignored without any complaints.
General syntax:
Tool set | Prefix for params | Example |
Boost Test | two dashes | –option_a=some_value |
TTB | one dash | -optionA or
-optionA someValueA |
Useful BoostTest command line params
Table of useful parameter setttings:
Boost Test Command | Purpose |
–log_level=test_suite | Boost Test will write more output, useful for better understanding of control flow and error conditions |
–run_test=SuiteA | run all test cases of your test suite with name "SuiteA" |
–run_test=SuiteA/TestCase3 | run only the single test case "TestCase3" within test suite with name "SuiteA" |
–run_test=SuiteDo*,*MyTop* | run all test suites with matching names, e.g. "SuiteDoSomething" and "SuiteForMyTopic" |
–detect_memory_leak=47 | for finding memory leaks specify the allocation number you have received from the memory leak dump after program termination, only to be used within debugger! |
Full list of command line params at Boost.org
TestToolBox command line params
When the TestToolBox is used in combination with Boost Test (i.e. TTB is running without its runtime framework TTB::TestRunner) there are no predefined command line params. But you can easily add params of your choice by using the possibilities within TestToolBox::Environment to access the command line:
- IsExistingCommandLineOption("-optionA")
Checks whether the given commmand line option is set
- GetCommandLineOptionVal<int>("-optionA")
converts the token following to -optionA to int type. You can convert to any basic type by setting a proper template type.
Table of possible / recommended parameter settings:
Recommended TTB Command | Purpose |
-prefixEvents TTB_EXP | If set different from empty string, then C++ syntax will be used for recording test events. Thus direct copying of text lines from test protocol file to your C++ test specification is posssible |
-suppressTopicA | You can skip code sections within your test script via checking
TTB::TheEnvironment()->IsExistingCommandLineOption("-suppressTopicA") |
-valX 17.2 | Read some value needed for testing (e.g. number of executions, values to use for some input to your test object,...) directly from command line using:
double valX = TTB::TheEnvironment()->GetCommandLineOptionVal<double>("-valX") |
Control recording of test events to prepare for copy to source code (-prefixEvents TTB_EXP)
With setting command line param "-prefixEvents TTB_EXP" you can set the output format of recorded test events to allow direct copying of selected lines from test protocol to the test cases within your C++ source code.
- The exact syntax for the name of the option ("-prefixEvents") has to be defined within your global test fixture, see Example for global test fixture.
- The needed option value ("TTB_EXP") depends on the check macro which you are using within the test case you are working on. You can vary the option to other values (e.g. "TTB_EXP_VAR") as you need it.
- Resulting entry within test protocol is:
TTB_EXP("someVal=3.14");
- (more readable) protocol entry without this option:
>someVal=3.14
Activate/deactivate sections of your test code (-suppressTopicA)
Depending on the runtime environment (e.g. development computer, cruise control, nightly build) you may want to deactivate portions of your test cases. Possible reasons could be:
- skip time consuming actions
- skip actions for which there is no runtime environment available at the current system
- skip experimental code you want to execute only sometimes, but for which you do not want to supply automatic verification
Example how to skip parts of a test case via option "-suppressSomething":
if (!TTB::TheEnvironment()->IsExistingCommandLineOption("-suppressDemoOutput"))
{
DemonstrateUsageOfPugiXml();
}
Retrieve numeric values from command line (-valX 17.2)
In a similar way you can use the command line to retrieve values for test execution (e.g. number of executions, values to use for some input to your test object,...).
Example how to read some value from command line:
double valX = TTB::TheEnvironment()->GetCommandLineOptionVal<double>("-valX");
TTB_INFO_S("command line param valX=" << valX);
Writing info messages to stdout and protocol files (TTB_OUT_S)
Sometimes it is useful to write informations to stdout while the test cases are executing. Instead of using "std::out" or BOOST_TEST_MESSAGE directly there is the more generic way of using macro TTB_OUT_S. This macro allows the selection of output targets (stdout, .out/.rpt files) and the messages can be switched off without changing any other outputs:
bool someCondition = false;
double pi = 3.14159265359;
TTB_OUT_S("This macro supports stream syntax x=" << std::setprecision(4) << pi
<< " condition=" << std::boolalpha << someCondition);
TTB_OUT_S("With default settings the output goes to .out + .rpt + stdout");
TTB::TheProtocol()->SelectTargetsForOutS(TTB::OutputMode::M_STDOUT);
TTB_OUT_S("After change of default settings this message goes only to stdout");
TTB::TheProtocol()->SelectTargetsForOutS(TTB::OutputMode::M_STDOUT | TTB::OutputMode::M_OUTFILE);
TTB_OUT_S("After another change of settings this message goes to .out + stdout");
TTB_T_OUT_S(TTB::OutputMode::M_STDOUT, "This message with explicit target goes to stdout");
TTB_T_OUT_S(TTB::OutputMode::M_OUTFILE| TTB::OutputMode::M_RPTFILE,
"This message with explicit targets goes to .out + .rpt");
TTB::TheProtocol()->SetVerbosityForOutS(TTB::OutputLevel::eVERBOUS);
TTB::TheProtocol()->SelectTargetsForOutS(TTB::OutputMode::M_STDOUT | TTB::OutputMode::M_OUTFILE | TTB::OutputMode::M_RPTFILE);
TTB_OUT_S("This verbous message goes to nowhere");
TTB::TheProtocol()->SetVerbosityForOutS(TTB::OutputLevel::eREGULAR);
TTB_OUT_S("And this regular message goes to out + rpt + stdout");
References