メモの日々


2018年03月15日(木) [長年日記]

[c++] Boost.Testのデータドリブンテストケース

Boost.Testのdata-driven test casesを使ってみたのでメモ。Boost 1.65.1 と g++ 6.3 を使用。

ドキュメントの辿り方が分かりにくいのだけれど、上でリンクしたページの先頭にある次のリンクの先に詳しい説明がある。

簡単なサンプル

#define BOOST_TEST_MODULE data driven test
#include <boost/test/included/unit_test.hpp>

#include <cmath>
#include <boost/test/data/test_case.hpp>

namespace bu = boost::unit_test;

BOOST_AUTO_TEST_SUITE(suite, * bu::tolerance(1e-16))

BOOST_DATA_TEST_CASE(
    sqrt_test,
    bu::data::xrange(0.0, 1.0, 0.1),
    a)
{
  const auto root = std::sqrt(a);
  BOOST_TEST(root * root == a);
}

BOOST_AUTO_TEST_SUITE_END()
  • std::sqrt(a)の2乗がaに等しくなるかをテストしている。
  • BOOST_DATA_TEST_CASE()の2番目の引数に「dataset」を与える。上ではxrange()を使って0.0~0.9までの10個の小数からなるdatasetを与えている。これにより、このテストケースは10回呼び出されることになる。
  • datasetの各要素の値はBOOST_DATA_TEST_CASE()の3番目の引数に代入される。

上のプログラムを実行すると次のように出力される。

Running 10 test cases...
data_test.cpp(17): error: in "suite/sqrt_test/_2": check root * root == a has failed [0.44721359549995793 * 0.44721359549995793 != 0.20000000000000001]. Relative difference exceeds tolerance [1.38778e-16 > 1e-16]
Failure occurred in a following context:
    a = 0.20000000000000001;
data_test.cpp(17): error: in "suite/sqrt_test/_3": check root * root == a has failed [0.54772255750516619 * 0.54772255750516619 != 0.30000000000000004]. Relative difference exceeds tolerance [1.85037e-16 > 1e-16]
Failure occurred in a following context:
    a = 0.30000000000000004;
data_test.cpp(17): error: in "suite/sqrt_test/_5": check root * root == a has failed [0.70710678118654757 * 0.70710678118654757 != 0.5]. Relative difference exceeds tolerance [2.22045e-16 > 1e-16]
Failure occurred in a following context:
    a = 0.5;
data_test.cpp(17): error: in "suite/sqrt_test/_6": check root * root == a has failed [0.7745966692414834 * 0.7745966692414834 != 0.59999999999999998]. Relative difference exceeds tolerance [1.85037e-16 > 1e-16]
Failure occurred in a following context:
    a = 0.59999999999999998;
data_test.cpp(17): error: in "suite/sqrt_test/_7": check root * root == a has failed [0.83666002653407556 * 0.83666002653407556 != 0.69999999999999996]. Relative difference exceeds tolerance [1.58603e-16 > 1e-16]
Failure occurred in a following context:
    a = 0.69999999999999996;

*** 5 failures are detected in the test module "data driven test"

誤差が生じるのでいくつかのテストは失敗している。

datasetを組み合わせる

datasetの組に対してjoinとzipとgridという操作をして新しいdatasetを生成できるようになっている。zipを使ったサンプルを示す。

#define BOOST_TEST_MODULE data driven test
#include <boost/test/included/unit_test.hpp>

#include <cmath>
#include <boost/test/data/test_case.hpp>

namespace bu = boost::unit_test;

BOOST_AUTO_TEST_SUITE(suite, * bu::tolerance(1e-16))

BOOST_DATA_TEST_CASE(
    sqrt_test2,
    bu::data::xrange(0.0, 1.0, 0.1) ^ bu::data::make(2),
    a,
    b)
{
  const auto root = std::sqrt(a);
  BOOST_TEST((root + b) * (root - b) == a - 4);
}

BOOST_AUTO_TEST_SUITE_END()
  • BOOST_DATA_TEST_CASE()の2番目の引数で使っている演算子「^」がzip操作を表す。これにより { {0.0, 2}, {0.1, 2}, {0.2, 2}, ..., {0.9, 2} } というdatasetが作られる。
  • datasetの各要素の1番目と2番目の値はそれぞれBOOST_DATA_TEST_CASE()の3番目と4番目の引数(aとb)に代入される。

datasetの組み合わせの組み合わせ

datasetに対する操作はネストさせることができるのだと思うけれど、少なくともzipした結果同士をjoinすると正しく動かないようで、チケットがあがっている。

手元の環境でチケットにあるコードを試すとsegmentation faultが発生してしまう。このチケットは現状で2か月放置されている。