<html>
<head>
<base href="https://wiki.asterisk.org/wiki">
<link rel="stylesheet" href="/wiki/s/en/2171/18/9/_/styles/combined.css?spaceKey=TOP&forWysiwyg=true" type="text/css">
</head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
<h2><a href="https://wiki.asterisk.org/wiki/display/TOP/Writing+Asterisk+SCF+Unit+Tests">Writing Asterisk SCF Unit Tests</a></h2>
<h4>Page <b>edited</b> by <a href="https://wiki.asterisk.org/wiki/display/~beagles">Brent Eagles</a>
</h4>
<br/>
<h4>Changes (2)</h4>
<div id="page-diffs">
<table class="diff" cellpadding="0" cellspacing="0">
<tr><td class="diff-snipped" >...<br></td></tr>
<tr><td class="diff-unchanged" >* test precondition checking <br> <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">The Boost Test Library was chosen for its broad platform support, flexibility and extensive set of test tools. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The Boost Test Library was chosen because: <br>* it supports a wide variety of platforms <br>* it is very flexible in how it can be employed <br>* it is extensive, containing a variety of programmatic tools for writing and performing tests <br>* adheres to good C\+\+ programming practices <br></td></tr>
<tr><td class="diff-unchanged" > <br>There are two forms of tests developed for Asterisk SCF components: unit tests and component tests. Unit tests are standalone executables, or IceBox services that directly invoke complex, fundamental or high risk code that is most effectively tested by accessing it as directly as possible. Component tests are all executed as IceBox services, manipulating the component being tested through its published external interfaces. This tutorial works through examples of each form. <br></td></tr>
<tr><td class="diff-snipped" >...<br></td></tr>
</table>
</div> <h4>Full Content</h4>
<div class="notificationGreySide">
<p>The unit and component tests for the Asterisk SCF employ the <a href="http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/index.html" class="external-link" rel="nofollow">Boost Test Library</a> for:</p>
<ul>
        <li>test output formatting</li>
        <li>test failure reporting</li>
        <li>test precondition checking</li>
</ul>
<p>The Boost Test Library was chosen because:</p>
<ul>
        <li>it supports a wide variety of platforms</li>
        <li>it is very flexible in how it can be employed</li>
        <li>it is extensive, containing a variety of programmatic tools for writing and performing tests</li>
        <li>adheres to good C++ programming practices</li>
</ul>
<p>There are two forms of tests developed for Asterisk SCF components: unit tests and component tests. Unit tests are standalone executables, or IceBox services that directly invoke complex, fundamental or high risk code that is most effectively tested by accessing it as directly as possible. Component tests are all executed as IceBox services, manipulating the component being tested through its published external interfaces. This tutorial works through examples of each form.</p>
<h2><a name="WritingAsteriskSCFUnitTests-CreatingaStandaloneExecutable"></a>Creating a Standalone Executable</h2>
<p>Standalone tests are useful for running tests that do not require multiple components or supported services, particularly for tests that exercise only internal interfaces (non-Ice-mediated).</p>
<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/information.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>Asterisk SCF does not contain many tests that run as stand-alone executables. Emphasis is generally given to verifying that the contracts prescribed by the Slice definitions are correctly implemented. IceBox test services are more appropriate for this kind of test. Stand alone tests tend to focus on verifying very specific code of a critical nature.</td></tr></table></div>
<p>There are three essential components to focus on when creating a standalone test:</p>
<ol>
        <li>The code being tested.</li>
        <li>The test code itself.</li>
        <li>The CMakeLists.txt file.</li>
</ol>
<p>While there are several examples of 1. in the Asterisk SCF source code, examining a contrived simple example makes the relevant points more clear.</p>
<h3><a name="WritingAsteriskSCFUnitTests-TheCodeBeingTested"></a>The Code Being Tested</h3>
<p>The example code is comprised of two files: a C++ header file and a C++ source file. The header file contains the declaration for an abstract base class and factory method for creating instances of an implementation of the base class. The class simply generates the next number in Fibonacci sequence each time it is called.</p>
<p>First the header file:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>Fibonacci.h</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; collapse: true; gutter: false">class FibonacciGenerator
{
public:
FibonacciGenerator();
unsigned next();
private:
unsigned mIndex;
unsigned mLast;
unsigned mBeforeThat;
};</pre>
</div></div>
<p>Now the source file:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>Fibonacci.cpp</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; collapse: true; gutter: false">#include "Fibonacci.h"
FibonacciGenerator::FibonacciGenerator() :
mIndex(0),
mLast(0),
mBeforeThat(0)
{
}
unsigned FibonacciGenerator::next()
{
if (mIndex == 0)
{
++mIndex;
return 0;
}
if (mIndex == 1)
{
++mIndex;
mLast = 1;
return 1;
}
unsigned result = mLast + mBeforeThat;
unsigned t = mLast;
mLast = result;
mBeforeThat = t;
return result;
}</pre>
</div></div>
<h3><a name="WritingAsteriskSCFUnitTests-TheTestCode"></a>The Test Code</h3>
<p>The complexity of the test code is often greater than expected, especially if the tests also cover error handling. For purposes of illustration the example test code is minimal. A proper test for a Fibonacci sequence generator might employ larger sets of data to be test as well as random checks against results computed by other means. </p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; collapse: true; gutter: false">#include "Fibonacci.h"
#define BOOST_TEST_MODULE FibonacciTest
#include <boost/test/unit_test.hpp>
#include <boost/test/debug.hpp>
#include <vector>
#include <string>
using namespace std;
//
// An example test fixture that does not really do anything.
//
class DefaultTestFixture
{
public:
DefaultTestFixture()
{
//
// If a collection of test cases required the same operations to
// setup required pre-conditions, they would be implemented in the
// constructor of a test fixture such as the one here.
//
cerr << "Entering test..." << endl;
}
~DefaultTestFixture()
{
//
// If a collection of test cases required the same operations to
// clean up after the test, they would be implemented in the
// destructor of a destructor of a test fixture such as the one
// here.
//
cerr << "Leaving test..." << endl;
}
};
BOOST_GLOBAL_FIXTURE(DefaultTestFixture);
BOOST_AUTO_TEST_CASE(check10Numbers)
{
FibonacciGenerator fibonacci;
vector<unsigned> results;
for (unsigned i = 0; i < 10; ++i)
{
results.push_back(fibonacci.next());
}
unsigned checkValues[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };
BOOST_REQUIRE((sizeof(checkValues)/ sizeof(checkValues[0])) == results.size());
for (unsigned j = 0; j < sizeof(checkValues)/sizeof(checkValues[0]); ++j)
{
BOOST_CHECK(checkValues[j] == results[j]);
}
}</pre>
</div></div>
<h3><a name="WritingAsteriskSCFUnitTests-TheCMakeLists.txtFile"></a>The CMakeLists.txt File</h3>
<p>Writing some code and some tests for that code are (hopefully) familiar to every developer no matter what the project or<br/>
background. cmake's CMakeLists.txt may not be as familiar and the Asterisk SCF specific cmake functions are sure to be<br/>
new.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">include_directories(../src)
astscf_component_init(FibonacciTestCL)
astscf_component_add_files(FibonacciTestCL
        TestFibonacci.cpp
        ../src/Fibonacci.cpp
        ../src/Fibonacci.h
        )        
astscf_component_add_boost_libraries(FibonacciTestCL unit_test_framework thread)
astscf_component_build_standalone(FibonacciTestCL)
astscf_test_boost(FibonacciTestCL)</pre>
</div></div>
<p><em>The test is named FibonacciTestCL to denote a command line interface and distinguish it from the FibonacciTest component declared later on.</em></p>
<p>For the most part, the Asterisk SCF CMake functions are the same as for non-test related applications. <tt>astscf_test_boost()</tt> is the test specific CMake function – it identifies this target as a test application to be executed by ctest.</p>
<h2><a name="WritingAsteriskSCFUnitTests-IceBoxTests"></a>IceBoxTests</h2>
<p>Asterisk SCF components are deployed as IceBox services. IceBox services can be configured to load in a specific order, allowing component tests to be deployed as a service that is loaded <em>after</em> the component being tested.</p>
<p>Integrating the IceBox service startup process and the boost test framework is not difficult, but it is tedious. The Asterisk SCF <b>ice-util-cpp</b> library contains an <tt>IceBox::Service</tt> derived base class, <tt>IceBoxTest</tt> which contains an implementation of IceBox::Service::start() that invokes the unit test framework's start method. The unit test can then be implemented using the usual Boost unit test framework mechanisms.</p>
<p>An example similar in functionality to the standalone example is a little more complicated as it involves IceBox services and Ice related code. The example is comprised of a Slice definition, a C++ file containing the service implementation and a C++ file containing the test code. There are also additional CMakeLists.txt file to build the separate parts as well as an IceBox configuration file to load and configure the services.</p>
<p>First the Slice definition. Notice the similarities to the <tt>FibonacciGenerator</tt> class in the standalone example. The reset method was added because there is only one instance of the generator running for this example and it helps illustrate the role of fixtures later on.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>AsteriskSCF/Number/FibonacciIf.ice</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; collapse: true; gutter: false">#pragma once
module AsteriskSCF
{
module Number
{
interface FibonacciGenerator
{
long next();
void reset();
};
}; /* End of module Number */
}; /* End of module AsteriskSCF */</pre>
</div></div>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>src/Fibonacci.cpp</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; collapse: true; gutter: false">#include <AsteriskSCF/Number/FibonacciIf.h>
#include <Ice/Ice.h>
#include <IceBox/IceBox.h>
class FibonacciGenerator : public AsteriskSCF::Number::FibonacciGenerator
{
public:
FibonacciGenerator() :
mIndex(0),
mLast(0),
mBeforeThat(0)
{
}
long next(const Ice::Current&)
{
IceUtil::Mutex::Lock lock(mLock);
if (mIndex == 0)
{
++mIndex;
return 0;
}
if (mIndex == 1)
{
++mIndex;
mLast = 1;
return 1;
}
long result = mLast + mBeforeThat;
long t = mLast;
mLast = result;
mBeforeThat = t;
return result;
}
void reset(const Ice::Current&)
{
IceUtil::Mutex::Lock lock(mLock);
mLast = 0;
mBeforeThat = 0;
mIndex = 0;
}
private:
IceUtil::Mutex mLock;
long mIndex;
long mLast;
long mBeforeThat;
};
class FibonacciService :: IceBox::Service
{
public:
void start(const string& name, const Ice::CommunicatorPtr& communicator, const Ice::StringSeq& args)
{
mAdapter = communicator->createObjectAdapter(name);
AsteriskSCF::Number::FibonacciGeneratorPtr fibonacci = new FibonacciGenerator;
mAdapter->add(fibonacci, communicator->stringToIdentity("fibonacci"));
mAdapter->activate();
}
void stop()
{
if (mAdapter)
{
try
{
mAdapter->destroy();
}
catch (...)
{
}
}
}
protected:
Ice::ObjectAdapterPtr mAdapter;
};
extern "C"
{
ASTSCF_DLL_EXPORT IceBox::Service* create(Ice::CommunicatorPtr)
{
reutrn new FibonacciService;
}
}</pre>
</div></div>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>test/TestFibonacci.cpp</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; collapse: true; gutter: false">#define BOOST_TEST_MODULE FibonacciTest
#include <AsteriskSCF/Testing/IceBoxBoostTest.h>
#include <AsteriskSCF/Number/FibonacciIf.h>
#include <string>
#include <vector>
using namespace std;
//
// As we are always testing a fibonacci generator object, the test fixture can
// do the work of obtaining a proxy to it.
//
class DefaultTestFixture
{
public:
DefaultTestFixture()
{
Ice::ObjectPrx obj = IceBoxTestEnv.communicator->propertyToProxy("Fibonacci.Proxy");
BOOST_REQUIRE(obj);
//
// The checked cast may throw if an error occurs when reaching the server, but the
// UTF will handle that and report it as an error.
//
mFibonacci = AsteriskSCF::Number::FibonacciGeneratorPrx::checkedCast(obj);
BOOST_REQUIRE(mFibonacci);
}
~DefaultTestFixture()
{
//
// We want the next test to start out fresh, so we need to reset
// the generator.
//
try
{
mFibonacci->reset();
}
catch (...)
{
BOOST_MESSAGE("exception caught when resetting the generator");
}
mFibonacci = 0;
}
AsteriskSCF::Number::FibonacciGeneratorPrx mFibonacci;
};
BOOST_FIXTURE_TEST_CASE(check10Numbers, DefaultTestFixture)
{
vector<Ice::Long> results;
for (unsigned i = 0; i < 10; ++i)
{
results.push_back(mFibonacci->next());
}
Ice::Long checkValues[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };
BOOST_REQUIRE((sizeof(checkValues)/ sizeof(checkValues[0])) == results.size());
for (unsigned j = 0; j < sizeof(checkValues)/sizeof(checkValues[0]); ++j)
{
BOOST_CHECK(checkValues[j] == results[j]);
}
}</pre>
</div></div>
<p>As can be seen by the test code, the IceBoxBoost base class takes care of the Boost UTF setup as well as supplying an IceBox service implementation for launching the test. This eases the burden on test writers to the point where there is little difference in constructing standalone or IceBox tests.</p>
<p>The other key differences are in the construction of the CMakeLists.txt file for the test itself:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">include_directories(${astscf-ice-util-cpp_dir}/include)
astscf_slice_include_collection(NUMBER)
astscf_component_init(FibonacciTest)
astscf_component_add_files(FibonacciTest TestFibonacci.cpp)
astscf_component_add_slice_collection_libraries(FibonacciTest NUMBER)
astscf_component_add_boost_libraries(FibonacciTest unit_test_framework thread)
astscf_component_build_icebox(FibonacciTest)
target_link_libraries(FibonacciTest astscf-ice-util-cpp)
astscf_test_icebox(FibonacciTest config/test_fibonacci.icebox)</pre>
</div></div>
<p><tt>astscf_test_icebox()</tt> takes the place of <tt>astscf_test_boost()</tt> that was used in the standalone example. In addition to identifying the target as a test, it also requires a second argument which is the path to the IceBox configuration file. This path is relative to the root of the component's source directory.</p>
<p>The other critical part of the an IceBox service as test driver is the IceBox configuration file.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">#
# IceBox service configuration file for the fibonacci number generator
#
# All services loaded by this configuration file should also load these
# properties.
IceBox.InheritProperties=1
Fibonacci.Proxy=fibonacci:default -h 127.0.0.1 -p 3333
IceBox.Service.FibonacciGenerator=FibonacciGenerator:create
FibonacciGenerator.Endpoints=default -h 127.0.0.1 -p 3333
IceBox.Service.FibonacciTest=FibonacciTest:create
IceBox.LoadOrder=FibonacciGenerator FibonacciTest</pre>
</div></div>
<p>For developers familiar with Ice and IceBox services, this contents of the configuration file should seem pretty standard. The important elements are <tt>IceBox.InheritProperties</tt> and <tt>IceBox.LoadOrder</tt>. The former ensures that the properties contained in the file are passed to each IceBox service loaded by the file. This is not strictly necessary, but it simplifies the management of test related configuration. The <tt>IceBox.LoadOrder</tt> property is important to ensure that each service is loaded in the proper order. In this simple example, there is a good chance that everything would work fine without this property. However, if several components must be loaded, some of which are dependent on each other in different ways, the load order of the services becomes very important.</p>
<h2><a name="WritingAsteriskSCFUnitTests-CTestRunningtheTests"></a>CTest - Running the Tests</h2>
<p>CTest is a test driver that is part of the <a href="http://www.cmake.org" class="external-link" rel="nofollow">CMake</a> build system <em>(for more information on CMake with Asterisk SCF, see <span class="error">[Asterisk SCF:Asterisk SCF and CMake howto]</span>)</em>. The Asterisk SCF CMake functions <tt>astscf_test_icebox}()} and {{astscf_boost_test()</tt> generate valid "test" targets for the relevant target build system. Building these test targets executes CTest with the appropriate configuration, capturing the test results and reporting the general success and failure of the tests. The test output can also be directed to <em>dashboard systems</em> which provide online viewing of test results. This facility is an integral part of the Asterisk SCF automated build and continuous integration system.</p>
<h2><a name="WritingAsteriskSCFUnitTests-boost%3A%3AtestTheBoostUnitTestFrameworkAQuickIntroduction"></a>boost::test - The Boost Unit Test Framework - A Quick Introduction</h2>
<p>The <a href="http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/utf.html" class="external-link" rel="nofollow">Boost unit test framework documentation</a> on the <a href="http://www.boost.org/" class="external-link" rel="nofollow">Boost website</a>. The documentation is generally quite good. A quick introduction to some of the test framework may help a developer get started more quickly.</p>
<h3><a name="WritingAsteriskSCFUnitTests-Fixtures"></a>Fixtures</h3>
<p>Fixtures are C++ classes or structs that take care of setting up the preconditions that are common to a set of tests as well as cleaning up and releasing resources when a test is over. In the Boost UTF (*u*nit *t*est *f*ramework), fixtures are expected to include all precondition code in the constructor and cleanup in the destructor. To avoid confusing results, it is important that the constructors and destructors are carefully written to not interfere with the overall running of the tests (e.g. exceptions are handled correctly, tests are failed immediately if an error condition occurs when setting up the preconditions, etc.). When used with supplied macros for defining test cases, a test case can be easily associated with a default global or specialized test.</p>
<p>A test fixture may look something like the following:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">//
// This test fixture is declared as a struct as all of its data members are
// meant to be publicly accessible to the test cases. In the boost UTF,
// tests associated with a fixture have access to the non-private members
// defined in that fixture.
//
struct DefaultTestFixture
{
DefaultTestFixture()
{
        cout << "DefaultTestFixture() - test setup\n";
}
~DefaultTestFixture()
{
        cout << "~DefaultTestFixture() - test teardown\n";
}
};</pre>
</div></div>
<p>You identify the a fixture as the global fixture using the <tt>BOOST_GLOBAL_FIXTURE</tt> macro.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">BOOST_GLOBAL_FIXTURE(DefaultTestFixture);</pre>
</div></div>
<p>This test fixture example simply prints a message to standard out. To add a test case that uses this fixture for setup and tear-down, define a test case using the <tt>BOOST_AUTO_TEST_CASE(<test case name>)</tt> macro.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">BOOST_AUTO_TEST_CASE(simpleNonsenseTest)
{
BOOST_CHECK(true);
}</pre>
</div></div>
<p><em>The BOOST_CHECK() macro was surreptitiously introduced here. It is described along with its counterparts further on.</em></p>
<h3><a name="WritingAsteriskSCFUnitTests-PertestFixture"></a>Per test Fixture</h3>
<p>In many situations it is more appropriate to define more than one test fixture for different test cases. How the fixture is written does not change, but how it is associated with a test case does. The <tt>BOOST_FIXTURE_TEST_CASE(<case name>, <fixture name>)</tt> declares a test case and associates it with the specified test fixture.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">BOOST_FIXTURE_TEST_CASE(simpleNonsenseTest, DefaultTestFixture)
{
BOOST_CHECK(true);
}</pre>
</div></div>
<h2><a name="WritingAsteriskSCFUnitTests-CommonMacros"></a>Common Macros</h2>
<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<td class='confluenceTd'> BOOST_TEST_CHECKPOINT </td>
<td class='confluenceTd'> Defines a named position that may be used by the Boost UTF when reporting exceptions. Useful for narrowing down the areas where errors are reported to have occurred. </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_TEST_PASSPOINT </td>
<td class='confluenceTd'> The boost documentation is currently bugged, but this appears somewhat similar to a checkpoint. </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_TEST_DONT_PRINT_LOG_VALUE(<em>arg type</em>) </td>
<td class='confluenceTd'> Declare that tests involving values of the type <em>arg type</em> do not attempt to print the values of the test operands. This is useful when using test macros for types that have a full complement of logical operands, but do not have a output stream inserter defined </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_TEST_MESSAGE </td>
<td class='confluenceTd'> Write the message to the current test log </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_TEST_CHECKPOINT("message here") </td>
<td class='confluenceTd'> Declare that the point at which the macro is declared should be remembered and identified by the "message here" string. It can be used by the exception reporting mechanisms if an error occurs </td>
</tr>
</tbody></table>
</div>
<p><b>The "test" macros</b><br/>
There are a series of macros that are a combination of severity level and the nature of the test. All macros begin with "BOOST_". All except "REQUIRE" continue execution. In other words, if there is no point in continuing the test if a condition fails, use the REQUIRE version of the test macro. A quick rundown of the current common test macros.</p>
<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> WARNING </th>
<th class='confluenceTh'> CHECK </th>
<th class='confluenceTh'> REQUIRE </th>
<th class='confluenceTh'> Description </th>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_BITWISE_EQUAL(a, b) </td>
<td class='confluenceTd'> BOOST_CHECK_BITWISE_EQUAL(a, b) </td>
<td class='confluenceTd'> BOOST_REQUIRE_BITWISE_EQUAL(a, b) </td>
<td class='confluenceTd'> bitwise comparsion of a and b </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_CLOSE(a, b, tolerance) </td>
<td class='confluenceTd'> BOOST_CHECK_CLOSE(a, b, tolerance) </td>
<td class='confluenceTd'> BOOST_REQUIRE_CLOSE(a, b, tolerance) </td>
<td class='confluenceTd'> checks if a and b are within tolerance of each other</td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_CLOSE_FRACTION(a, b, tolerance) </td>
<td class='confluenceTd'> BOOST_CHECK_CLOSE_FRACTION(a, b, tolerance) </td>
<td class='confluenceTd'> BOOST_REQUIRE_CLOSE_FRACTION(a, b, tolerance) </td>
<td class='confluenceTd'> checks if a and b are within a percentage of each other </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_EQUAL(a, b) </td>
<td class='confluenceTd'> BOOST_CHECK_EQUAL(a, b) </td>
<td class='confluenceTd'> BOOST_REQUIRE_EQUAL(a, b) </td>
<td class='confluenceTd'> checks for equality </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_EQUAL_COLLECTION(a_begin, a_end, b_begin, b_end) </td>
<td class='confluenceTd'> BOOST_CHECK_EQUAL_COLLECTION(a_begin, a_end, b_begin, b_end) </td>
<td class='confluenceTd'> BOOST_REQUIRE_EQUAL_COLLECTION(a_begin, a_end, b_begin, b_end) </td>
<td class='confluenceTd'> checks for equality of a range of values </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_CHECK_EXCEPTION(expr, exception, pred) </td>
<td class='confluenceTd'> BOOST_REQUIRE_EXCEPTION(expr, exception, pred) </td>
<td class='confluenceTd'> BOOST_X_EXCEPTION(expr, exception, pred) </td>
<td class='confluenceTd'> checks if an exception of a given type is thrown by exrp and it pred succeeds </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_GE(a, b) </td>
<td class='confluenceTd'> BOOST_CHECK_GE(a, b) </td>
<td class='confluenceTd'> BOOST_REQUIRE_GE(a, b) </td>
<td class='confluenceTd'> greater than or equal to </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_GT(a, b) </td>
<td class='confluenceTd'> BOOST_CHECK_GT(a, b) </td>
<td class='confluenceTd'> BOOST_REQUIRE_GT(a, b) </td>
<td class='confluenceTd'> greater than </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_LE(a, b) </td>
<td class='confluenceTd'> BOOST_CHECK_LE(a, b) </td>
<td class='confluenceTd'> BOOST_REQUIRE_LE(a, b) </td>
<td class='confluenceTd'> less than or equal to </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_LT(a, b) </td>
<td class='confluenceTd'> BOOST_CHECK_LT(a, b) </td>
<td class='confluenceTd'> BOOST_REQUIRE_LT(a, b) </td>
<td class='confluenceTd'> less than </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_MESSAGE(pred, msg) </td>
<td class='confluenceTd'> BOOST_CHECK_MESSAGE(pred, msg) </td>
<td class='confluenceTd'> BOOST_REQUIRE_MESSAGE(pred, msg) </td>
<td class='confluenceTd'> displays a message and affects flow and reporting according to the severity of th macro used </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_NE(a, b) </td>
<td class='confluenceTd'> BOOST_CHECK_NE(a, b) </td>
<td class='confluenceTd'> BOOST_REQUIRE_NE(a, b) </td>
<td class='confluenceTd'> not equal to </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_NO_THROW(expr) </td>
<td class='confluenceTd'> BOOST_CHECK_NO_THROW(expr) </td>
<td class='confluenceTd'> BOOST_REQUIRE_NO_THROW(expr) </td>
<td class='confluenceTd'> checks that no exception was thrown </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_PREDICATE(pred, args) </td>
<td class='confluenceTd'> BOOST_CHECK_PREDICATE(pred, args) </td>
<td class='confluenceTd'> BOOST_REQUIRE_PREDICATE(pred, args) </td>
<td class='confluenceTd'> checks that result of a predicate with the specified args </td>
</tr>
<tr>
<td class='confluenceTd'> BOOST_WARNING_THROW(expr, exception) </td>
<td class='confluenceTd'> BOOST_CHECK_THROW(expr, exception) </td>
<td class='confluenceTd'> BOOST_REQUIRE_THROW(expr, exception) </td>
<td class='confluenceTd'> checks that an exception of the specified type was thrown by expr </td>
</tr>
</tbody></table>
</div>
<p>More details on these and other test tools can be found on the <a href="http://www.boost.org" class="external-link" rel="nofollow">boost.org</a> website.</p>
<h3><a name="WritingAsteriskSCFUnitTests-AndOneMoreThing"></a>And One More Thing</h3>
<p>Test cases should not depend on being run in a particular order. The Boost UTF provides mechanisms to run tests in randomized order or selectively run certain tests. If a test case depends on the successful conclusion of other tests, these features may not be used. It is generally considered a bad practice to have test cases dependent on each other, so it is good to avoid in any case.</p>
<p><em>The source code for the examples in this wiki can be obtained at:</em></p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">git://git.asterisk.org/team/beagles/fibonacci-standalone</pre>
</div></div>
<p><em>and</em></p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">git://git.asterisk.org/team/beagles/fibonacci-icebox</pre>
</div></div>
</div>
<div id="commentsSection" class="wiki-content pageSection">
<div style="float: right;" class="grey">
<a href="https://wiki.asterisk.org/wiki/users/removespacenotification.action?spaceKey=TOP">Stop watching space</a>
<span style="padding: 0px 5px;">|</span>
<a href="https://wiki.asterisk.org/wiki/users/editmyemailsettings.action">Change email notification preferences</a>
</div>
<a href="https://wiki.asterisk.org/wiki/display/TOP/Writing+Asterisk+SCF+Unit+Tests">View Online</a>
|
<a href="https://wiki.asterisk.org/wiki/pages/diffpagesbyversion.action?pageId=19007285&revisedVersion=16&originalVersion=15">View Changes</a>
|
<a href="https://wiki.asterisk.org/wiki/display/TOP/Writing+Asterisk+SCF+Unit+Tests?showComments=true&showCommentArea=true#addcomment">Add Comment</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>