I am extending a library for computational fluid dynamics, so I am dealing with legacy code. The applications involve initializing sometimes very large objects, most of which are codependent. The initialization is dependent on configuration and input files stored in a directory.
Trying to use a testing framework compared to my own testing hacked libs should make sense, since there are various test cases and families, and tests, and I could benefit from having the test tree and shiny reports + ability to automatize the tests.
However, I heve encountered a problem when trying to call specific tests at specific points in the program. This problem has occured already when I tried using Google Test - see this question.
Here is a model of the problem using Boost.Test:
#define BOOST_TEST_MODULE hugeObjectEvenTest
#define BOOST_TEST_NO_MAIN
#include <boost/test/included/unit_test.hpp>
#include<random>
#include<iostream>
BOOST_AUTO_TEST_SUITE (hugeObjectEvenTest)
BOOST_AUTO_TEST_CASE (test1)
{
BOOST_CHECK(hugeObject.value() % 2 == 0);
}
BOOST_AUTO_TEST_SUITE_END()
class HugeClass
{
int value_ = 0;
public:
HugeClass() = default;
HugeClass(int x) : value_(x) {};
int value () { return value_; }
void setValue (int val) { value_ = val; }
};
int main(int argc, const char *argv[])
{
HugeClass hugeObject;
std::random_device rd;
std::default_random_engine e1(rd());
std::uniform_int_distribution<int> dist(0,100);
for(int i = 0; i < 10; ++i)
{
hugeObject.setValue(dist(e1));
std::cout << hugeObject.value() << std::endl;
}
return 0;
}
This is merely a model of a numerical solver application, like the one found here.
What I think I need is a global fixture, that is able to take a reference to the hugeObject
.
The instances just like hugeObject
are modified (modeled with random number generation) during the simulation, within the simulation loop (modeled with the for loop).
All I want to do, is to execute specific tests at specific points within main, and benefit from having a test tree, and all the other perks of using a testing framework. Something similar to the functionality of the Minimal Test Facility.
Is this at all possible with Boost.Test? Like Google Test, selecting specific tests can be done by parsing during execution. This is of no use whatsoever for my problem. I have used both GTest and BoostTest for unit tests, where the initialization of fixtures is local and not dependent on main (argc, argv, configuration and input files), and I had no problems.
Edit: I will get flamed for this probably, but when dealing with legacy code, I believe it would be beneficial to somehow be able to access the objects in main via const refs (to ensure that the tests don't modify objects), in a simpler way than inheriting from fixture classes. In my case, doing that means a day of work, compared to simple BOOST_TEST_REQUIRE placed within main when using the minimal testing framework. Of course, with the minimal framework I have no test tree, etc, so I am back where I started: at my own hacked test lib.
One possible way to do this is to perform your own manual test registration, separate the tests you want to execute together into suites and run them manually. For example:
using namespace boost::unit_test;
void test1() { std::cout << "Running test 1\n"; }
void test2() { std::cout << "Running test 2\n"; }
void test3() { std::cout << "Running test 3\n"; }
void init_test_tree() {
test_suite *ts1 = BOOST_TEST_SUITE( "suite_a");
ts1->add( BOOST_TEST_CASE( &test1 ) );
ts1->add(BOOST_TEST_CASE( &test2 ));
framework::master_test_suite().add(ts1);
test_suite *ts2 = BOOST_TEST_SUITE( "suite_b");
ts2->add( BOOST_TEST_CASE( &test3 ) );
framework::master_test_suite().add(ts2);
}
bool empty_init() { return true; }
int main( int argc, char *argv[] ) {
init_test_tree();
std::cout << "Run suite a\n";
framework::run( framework::master_test_suite().get("suite_a"));
std::cout << "Run suite b\n";
framework::run( framework::master_test_suite().get("suite_b"));
std::cout << "Run the tree\n";
// pass empty initialization function as we've already constructed the test tree
return unit_test_main(&empty_init, argc, argv);
}