In Boost.Test, I'd like to test a function for different values, each value associated to an expected result.
Something like (I know, the test is stupid):
void SquareTest(int expectedResult, int input)
{
BOOST_CHECK_EQUAL(expectedResult, MySquareFunctionToTest(input));
}
BOOST_AUTO_FUNCTION_TEST_CASE(SquareTest, 4, 2);
BOOST_AUTO_FUNCTION_TEST_CASE(SquareTest, 9, 3);
BOOST_AUTO_FUNCTION_TEST_CASE(SquareTest, 16, 4);
Is there a way to do that with Boost.Test ? The parametrized section int the documentation doesn't seem to match to my need.
I would suggest the simple:
#define BOOST_TEST_MODULE MyTest
#include <boost/test/unit_test.hpp>
int MySquareFunctionToTest(int x) { return x * x; }
void SquareTest(int expectedResult, int input) {
BOOST_CHECK_EQUAL(expectedResult, MySquareFunctionToTest(input));
}
BOOST_AUTO_TEST_CASE(SquareTest1) { SquareTest(4, 2); }
BOOST_AUTO_TEST_CASE(SquareTest2) { SquareTest(9, 3); }
BOOST_AUTO_TEST_CASE(SquareTest3) { SquareTest(16, 4); }
If you really feel like getting the Enterprise(TM) version on:
These were added for very good rationale, that probably resonate with you, since you were asking this question:
The approach above has several drawbacks:
- the logic for running the tests is inside a test itself: single_test in the above example is run from the test case combined_test while its execution would be better handled by the Unit Test Framework
- in case of fatal failure for one of the values in param array above (say a failure in BOOST_TEST_REQUIRE), the test combined_test is aborted and the next test-case in the test tree is executed.
- in case of failure, the reporting is not accurate enough: the test should certainly be reran during debugging sessions by a human or additional logic for reporting should be implemented in the test itself.
(and much more)
Example:
#include <boost/test/data/test_case.hpp>
namespace bdata = boost::unit_test::data;
BOOST_DATA_TEST_CASE(SquareDataDrivenTest, bdata::make({2, 3, 4}), input) {
SquareTest(input * input, input);
}
Of course, that's cheating. While
bdata::make({std::pair{2, 4}, {3, 9}, {4, 16}})
will work, it would require you to add printability to std::pair
. To avoid that, consider:
struct Params {
int a, a_squared;
friend std::ostream& operator<<(std::ostream& os, const Params& p){
return os << "a=" << p.a << ", a_squared=" << p.a_squared;
}
};
BOOST_DATA_TEST_CASE(SquareDataDrivenTest2, //
bdata::make({Params{2, 4}, {3, 9}, {4, 16}}), //
input) {
auto [a, a2] = input;
SquareTest(a2, a);
}
https://coliru.stacked-crooked.com/a/8cbcc9f6bfb967b1
#define BOOST_TEST_MODULE MyTest
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_parameters.hpp>
int MySquareFunctionToTest(int x) { return x * x; }
void SquareTest(int expectedResult, int input) {
BOOST_CHECK_EQUAL(expectedResult, MySquareFunctionToTest(input));
}
BOOST_AUTO_TEST_CASE(SquareTest1) { SquareTest(4, 2); }
BOOST_AUTO_TEST_CASE(SquareTest2) { SquareTest(9, 3); }
BOOST_AUTO_TEST_CASE(SquareTest3) { SquareTest(16, 4); }
// Now doing these with Data-Driven test cases:
#include <boost/test/data/test_case.hpp>
namespace bdata = boost::unit_test::data;
BOOST_DATA_TEST_CASE(SquareDataDrivenTest, bdata::make({2, 3, 4}), input) {
SquareTest(input * input, input);
}
struct Params {
int a, a_squared;
friend std::ostream& operator<<(std::ostream& os, const Params& p){
return os << "a=" << p.a << ", a_squared=" << p.a_squared;
}
};
BOOST_DATA_TEST_CASE(SquareDataDrivenTest2, //
bdata::make({Params{2, 4}, {3, 9}, {4, 16}}), //
input) {
auto [a, a2] = input;
SquareTest(a2, a);
}
Printing:
Running 9 test cases...
*** No errors detected
Or, -l all
:
Running 9 test cases...
Entering test module "MyTest"
/home/sehe/Projects/stackoverflow/test.cpp(11): Entering test case "SquareTest1"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
/home/sehe/Projects/stackoverflow/test.cpp(11): Leaving test case "SquareTest1"; testing time: 21us
/home/sehe/Projects/stackoverflow/test.cpp(12): Entering test case "SquareTest2"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
/home/sehe/Projects/stackoverflow/test.cpp(12): Leaving test case "SquareTest2"; testing time: 18us
/home/sehe/Projects/stackoverflow/test.cpp(13): Entering test case "SquareTest3"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
/home/sehe/Projects/stackoverflow/test.cpp(13): Leaving test case "SquareTest3"; testing time: 18us
/home/sehe/Projects/stackoverflow/test.cpp(20): Entering test suite "SquareDataDrivenTest"
/home/sehe/Projects/stackoverflow/test.cpp(20): Entering test case "_0"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
Assertion occurred in a following context:
input = 2;
/home/sehe/Projects/stackoverflow/test.cpp(20): Leaving test case "_0"; testing time: 20us
/home/sehe/Projects/stackoverflow/test.cpp(20): Entering test case "_1"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
Assertion occurred in a following context:
input = 3;
/home/sehe/Projects/stackoverflow/test.cpp(20): Leaving test case "_1"; testing time: 18us
/home/sehe/Projects/stackoverflow/test.cpp(20): Entering test case "_2"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
Assertion occurred in a following context:
input = 4;
/home/sehe/Projects/stackoverflow/test.cpp(20): Leaving test case "_2"; testing time: 17us
/home/sehe/Projects/stackoverflow/test.cpp(20): Leaving test suite "SquareDataDrivenTest"; testing time: 62us
/home/sehe/Projects/stackoverflow/test.cpp(32): Entering test suite "SquareDataDrivenTest2"
/home/sehe/Projects/stackoverflow/test.cpp(32): Entering test case "_0"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
Assertion occurred in a following context:
input = a=2, a_squared=4;
/home/sehe/Projects/stackoverflow/test.cpp(32): Leaving test case "_0"; testing time: 19us
/home/sehe/Projects/stackoverflow/test.cpp(32): Entering test case "_1"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
Assertion occurred in a following context:
input = a=3, a_squared=9;
/home/sehe/Projects/stackoverflow/test.cpp(32): Leaving test case "_1"; testing time: 18us
/home/sehe/Projects/stackoverflow/test.cpp(32): Entering test case "_2"
/home/sehe/Projects/stackoverflow/test.cpp(8): info: check expectedResult == MySquareFunctionToTest(input) has passed
Assertion occurred in a following context:
input = a=4, a_squared=16;
/home/sehe/Projects/stackoverflow/test.cpp(32): Leaving test case "_2"; testing time: 18us
/home/sehe/Projects/stackoverflow/test.cpp(32): Leaving test suite "SquareDataDrivenTest2"; testing time: 60us
Leaving test module "MyTest"; testing time: 193us
*** No errors detected
Note how the data driven test cases report context with their invocations.