5

I'm learning how to use Boost Test.

I want to test the method JulianToGreenWich(float jd):

#include <ctime>

class Convert
{
private:

public:
    Convert();
    ~Convert();

    tm JulianToGreenWich(float jd);
};

To test it with Boost Test, I have written down this code:

struct TestFixture
{
    Convert convert_instance;

    TestFixture()
        : convert_instance()
    {}

    ~TestFixture() = default;
};

BOOST_FIXTURE_TEST_SUITE(TestConvert, TestFixture)

BOOST_AUTO_TEST_CASE(julianToGreenWichCase)
{
  BOOST_TEST(1 == 1);
  BOOST_TEST(true);
}

My problem is that I want to test it with many (more than one) values. To do it, I've been reading about BOOST_DATA_TEST_CASE_F, but it seems that it needs a dataset (and I don't know how to create one and use it). So, I have started to read this at boost documentation: Datasets. But its example of a Example of custom dataset is very complicated.

If I want to check that is a pass a value (a float) to JulianToGreenWich method a I will get a get an specific tm struct.

How can I test my method with many pair values (float jd, tm)?

VansFannel
  • 45,055
  • 107
  • 359
  • 626

2 Answers2

3

The official documentation of Boost.Test is on www.boost.org: here.

Something like the following does:

  • creates 2 datasets
    • the first dataset - as an example - will contain the input values to the converter
    • the second dataset will contain the expected values
  • those two datasets are then combined into one unique with the zip operation on datasets, as explained here
  • each element after that is of arity 2, they are expanded in that order in the two variables given to BOOST_DATA_TEST_CASE, respectively input_value and expected_value
BOOST_DATA_TEST_CASE( test_convert, 
  data::make({0.1f,0.2f,0.3f})^data::make({tm1,tm2,tm3}), // creates a zip of 2 datasets
  input_value, // first variable of the zip
  expected_value) // second variable of the zip
{
  Convert convertInstance;
  // this might fail to compile because tm type should not printable.
  // Adding BOOST_TEST_DONT_PRINT_LOG_VALUE on the tm type before the test
  // should solve the issue.
  BOOST_TEST(convertInstance(input_value) == expected_value); 
}

You can replace BOOST_DATA_TEST_CASE by BOOST_DATA_TEST_CASE_F and use your fixture with the inherited convert_instance.

More about logging specific types can be found here.

Raffi
  • 3,068
  • 31
  • 33
0

IMO, boost::test is over-engineered and poorly documented, but it is still usable with its most basic core features, so that one doesn't need to install another library just for unit testing when boost is available.

One simple way is to defined a table with inputs and expected outputs and then use that table in the unit test:

#include <ctime>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Convert
#include "boost/test/unit_test.hpp"

namespace {

struct Convert {
    tm JulianToGreenWich(float jd);
};

tm make_tm(int year, int month, int day) {
    tm t = {};
    t.tm_year = year - 1900;
    t.tm_mon = month - 1;
    t.tm_mday = day;
    return t;
}

struct Test {
    float input;
    tm expected_output;
};

Test tests[] = {
    {         0.f, make_tm(1970, 1,  1)},
    {1560244906.f, make_tm(2019, 6, 11)},
};

BOOST_AUTO_TEST_CASE(my_test) {
    Convert c;
    for(auto& test : tests) {
        tm output = c.JulianToGreenWich(test.input);
        BOOST_CHECK_EQUAL(mktime(&output), mktime(&test.expected_output));
    }
}

} // namespace
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    Thanks for your answer. I also think it's poorly documented. BOOST_DATA_TEST_CASE_F and Dataset have confused me. – VansFannel Jun 11 '19 at 10:11