Home > The Unit Test Framework > User's guide > Test organization > Unary function based test case
PrevNext

Unary function based test case

Some tests are required to be repeated for a series of different input parameters. One way to achieve this is manually register a test case for each parameter as in example above. You can also invoke a test function with all parameters manually from within your test case, like this:
有些測試需要對一系列不同的輸入參數進行重複。 一種方法是像之前例子對每個參數手動註冊一個測試用例。 或者像這樣手動在一個測試函數中手動處理所有的參數:

void single_test( int i )
{
    BOOST_CHECK( /* test assertion */ );
}

void combined_test()
{
    int params[] = { 1, 2, 3, 4, 5 };

    std::for_each( params, params+5, &single_test );
}

The UTF presents a better solution for this problem: the unary function based test case, also referred as parameterized test case. The unary test function can be a free function, unary functor (for example created with boost::bind) or unary method of a class with bound test class instance). The test function is converted into test case using the macro BOOST_PARAM_TEST_CASE. The macro expects a collection of parameters (passed as two input iterators) and an unary test function:
UTF 為這個問題提供了更好的解決方案:基於單參函數的測試用例,也被稱為參數化測試用例。 參單測試用例可以是自由函數,單參函數對像 (如由 boost::bind 創建) 或者綁定於測試類實例的單參類方法。 測試函數使用宏 BOOST_PARAM_TEST_CASE 轉換為測試用例。 這個宏需要參數集合 (以兩個輸入迭代器形式輸入) 和單參測試函數:

BOOST_PARAM_TEST_CASE(test_function, params_begin, params_end)

BOOST_PARAM_TEST_CASE creates an instance of the test case generator. When passed to the method test_suite::add, the generator produces a separate sub test case for each parameter in the parameters collection and registers it immediately in a test suite. Each test case is based on a test function with the parameter bound by value, even if the test function expects a parameter by reference. The fact that parameter value is stored along with bound test function releases you from necessity to manage parameters lifetime. For example, they can be defined in the test module initialization function scope.
BOOST_PARAM_TEST_CASE 創建了一個測試類生成器的實例。 當傳遞到 test_suite::add 方法中時,生成器為參數集合中每個參數生成獨立的子測試用例並直接註冊到測試套件中。 每個測試用例都是基於測試函數和按值綁定的參數,即使測試函數需要引用的參數。 參數值和被綁定的測試函數一起存儲使你不必管理參數的生命週期。 例如,它們可以被定義在測試模塊初始化函數範圍內。

All sub test case names are deduced from the macro argument test_function. If you prefer to assign different names, you have to use the underlying make_test_case interface instead. Both test cases creation and registration are performed in the test module initialization function.
所有子測試用例的名稱都是通過宏參數 test_function 推斷的。 如果你想要指定不同的名稱,你需要使用下層的 make_test_case 接口。 測試用例的創建和註冊都是在測試模塊初始化函數中進行的。

The parameterized test case facility is preferable to the approach in the example above, since execution of each sub test case is guarded and counted independently. It produces a better test log/results report (in example above in case of failure you can't say which parameter is at fault) and allows you to test against all parameters even if one of them causes termination a particular sub test case.
參數化測試用例工具優於上面的例子,因為每個子測試用例都是獨立臨近和計數的。 它可以產生更好的測試日誌 / 結果報告 (上面例子中如果失敗沒有辦法知道在哪個參數時失敗的),並且即使在某個子測試用例中斷時也可以測試所有的參數。

In comparison with a manual test case registration for each parameter approach the parameterized test case facility is more concise and easily extendible.
與為每個參數手動註冊測試用例相比,參數化測試用例工具更簡練和易於擴展。

In following simple example the same test, implemented in free_test_function, is performed for 5 different parameters. The parameters are defined in the test module initialization function scope. The master test suite contains 5 independent test cases.
在下面的示例中,free_test_function 實現的同樣的測試應用於 5 個不同參數。 參數定義在測試模塊初始化函數範圍內。主測試套件包含 5 個相互獨立的測試用例。

Example 11. Unary free function based test case

#include <boost/test/included/unit_test.hpp>
#include <boost/test/parameterized_test.hpp>
using namespace boost::unit_test;

//____________________________________________________________________________//

void free_test_function( int i )
{
    BOOST_CHECK( i < 4 /* test assertion */ );
}

//____________________________________________________________________________//

test_suite*
init_unit_test_suite( int argc, char* argv[] )
{
    int params[] = { 1, 2, 3, 4, 5 };

    framework::master_test_suite().
        add( BOOST_PARAM_TEST_CASE( &free_test_function, params, params+5 ) );

    return 0;
}

//____________________________________________________________________________//
Source code | Show output
> example
Running 5 test cases...
test.cpp(9): error in "free_test_function": check i < 4 failed
test.cpp(9): error in "free_test_function": check i < 4 failed

*** 2 failures detected in test suite "Master Test Suite"

Next example is similar, but instead of a free function it uses a method of a class. Even though parameters are passed into test method by reference you can still define them in the test module initialization function scope. This example employs the alternative test module initialization function specification.
下面的例子類似,只是用類方法代替了自由函數。 即使參數是通過引用傳入測試方法中的,你也可以將它們定義在測試模塊初始化函數範圍中。 這個例子使用了備選的測試模塊初始化函數簽名。

Example 12. Unary class method based test case

#define BOOST_TEST_ALTERNATIVE_INIT_API
#include <boost/test/included/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/parameterized_test.hpp>
#include <boost/bind.hpp>
using namespace boost::unit_test;
using namespace boost;

//____________________________________________________________________________//

class test_class {
public:
    void test_method( double const& d )
    {
        BOOST_CHECK_CLOSE( d * 100, (double)(int)(d*100), 0.01 );
    }
} tester;

//____________________________________________________________________________//

bool init_unit_test()
{
    double params[] = { 1., 1.1, 1.01, 1.001, 1.0001 };

    callback1<double> tm = bind( &test_class::test_method, &tester, _1);

    framework::master_test_suite().
        add( BOOST_PARAM_TEST_CASE( tm, params, params+5 ) );

    return true;
}

//____________________________________________________________________________//

Source code | Show output
> example
Running 5 test cases...
test.cpp(14): error in "tm": difference between d * 100{100.1} and (double)(int)(d*100){100} exceeds 0.01%
test.cpp(14): error in "tm": difference between d * 100{100.01} and (double)(int)(d*100){100} exceeds 0.01%

*** 2 failures detected in test suite "Master Test Suite"


PrevUpHomeNext