Boost logo

Boost :

From: Gennadiy Rozental (rogeeff_at_[hidden])
Date: 2007-12-23 21:16:25


"Jens Seidel" <jensseidel_at_[hidden]> wrote in message
news:20071221141109.GB9314_at_imkf-pc073.imkf.tu-freiberg.de...
> On Fri, Dec 21, 2007 at 02:51:40AM -0500, Gennadiy Rozental wrote:
>> "Jens Seidel" <jensseidel_at_[hidden]> wrote in message
>> news:20071220161635.GA515_at_imkf-pc073.imkf.tu-freiberg.de...
>> > I read most of the new documentation but to make it short: I still fail
>> > to use unit tests. It worked in the past but after a lot of changes
>> > in Boost.Tests it is now unusable for me.
>>
>> Let's see concrete examples.
>
> Old code was as simple as:
>
> #include <boost/test/unit_test.hpp>
> using boost::unit_test::test_suite;
>
> test_suite* Jacobi_test_suite();

where this function is defined? Why can't you automatically register your
test units?

> test_suite* init_unit_test_suite(int, char *[])
> {
> Initialize_logging();

This should go into global fixture

> test_suite *test = BOOST_TEST_SUITE("Master test suite");
> test->add(Jacobi_test_suite());
> return test;
> }
>
>> >> > prefer to define main youself and invoke init function you can do it
>> >> > as
>> >> > well
>> >> > with shared library variant.
>> >
>> > And how?
>>
>> See example 9 on
>>
>> http://www.patmedia.net/~rogeeff/html/utf/user-guide/test-organization/manual-nullary-test-case.html
>
> Right. Thanks! Just changing
>
> test_suite* init_unit_test_suite(int, char *[])
> {
> Initialize_logging();
> test_suite *test = BOOST_TEST_SUITE("Master test suite");
> test->add(Jacobi_test_suite());
> return test;
> }
>
> into
>
> bool init_unit_test()
> {
> Initialize_logging();
>
> boost::unit_test::framework::master_test_suite().add(Jacobi_test_suite());
>
> return true;
> }
>
> int main(int argc, char *argv[])
> {
> return ::boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
> }
>
> works. Please note that one has to read dozens of pages before as this
> is nearly at the end of the documentation.
>
> Is this kind of usage really so difficult that you think it is worth the
> effort to hide it for the user and suggest automatic registration
> instead?

Yes. I believe you describing an extreme case. At this point there are no
good/common reasons to implement your test module like this. The only one I
can think of if you want to manage what test unis to execute yourself within
init function for some reason. Everything else can be done more efficiently
with aut-registration facilities. Another reason is that the test module
might be written already in old style. In this case you might not want to
invest time into converting it. Boost.Test still supprots it. But it
requires small changes in case if you were using shared library.

>> > Including the header boost/test/included/unit_test.hpp *once* per
>> > binary
>> > seems
>> > to work but normal using of boost/test/unit_test.hpp together with an
>> > additional
>> > #define BOOST_TEST_DYN_LINK
>> > still leads to a missing main() function. I get since 1.34.1:
>> > /usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/crt1.o: In function
>> > `_start':
>> > (.text+0x18): undefined reference to `main'
>> > collect2: ld returned 1 exit status
>>
>> You also need to define either BOOST_TEST_MODULE or BOOST_TEST_MAIN if
>> you
>> want Boost.Test to generate main function for you. Like in an example 18
>> here:
>>
>> http://www.patmedia.net/~rogeeff/html/utf/user-guide/test-organization/master-test-suite.html
>
> That's completely different from my current code. I will definitevly not
> use it as it uses too many macros (BOOST_TEST_MODULE,
> BOOST_AUTO_TEST_CASE and the probably required BOOST_TEST_DYN_LINK). It

You are mixing in a lot of different concepts. Each macro serve it's purpose
and only used when required.

> seems also impossible for me to use template functions as tests (which I
> currently use:
> template<bool var> void JacobiTest2();
> test->add(BOOST_TEST_CASE(&JacobiTest2<true>));
> test->add(BOOST_TEST_CASE(&JacobiTest2<false>));

I don't see any problems doing above. But the UTF provides better way to
implement this through test case template support. It has both automated and
manual registration.

> Macros are evil!

They might be, but they might be also a quite powerfull code generation
tool. The Boost.Test is very carefull in how it's defines and names macros.
I might find it difficult to avoid them, since more than 80% of library
interfaces is based on macros.

>> > I also defined BOOST_TEST_DYN_LINK on the comandline to ensure that all
>> > code
>> > uses it. Same result! Defining addionally BOOST_TEST_MAIN results in a
>> > a proper empty test with the output
>> > "Test setup error: test tree is empty"
>>
>> Because BOOST_TEST_MAIN produces both function main and empty init
>> function.
>
> According to
> http://www.patmedia.net/~rogeeff/html/utf/compilation.html#utf.flag.main:
> BOOST_TEST_MAIN Define this flag to generate an empty test module
> initialization function.
>
> I do not read anything about main().

Hmmmm. It's realy early in documentation to alk about complications like
this. I've added statement in this regard. Let me know if it's clearer now
(I'll post updated docs later today)

>> It's assumed that test units are automatically registered.
>
> I don't see many advantages as it only saved a single line of code and
> requires just another macro.

It saves much more than 1 line.

Compare:

void my_test_case()
{
   ...
}

bool init_unit_test()
{
    boost::unit_test::framework::master_test_suite().add(Jacobi_test_suite());

    return true;
}

with

BOOST_AUTO_TEST_CASE( my_test_case )
{
 ...
}

>> > Short: In the past it was so simple:
>> >
>> > #include <boost/test/unit_test.hpp>
>> > using boost::unit_test::test_suite;
>> > test_suite* init_unit_test_suite(int, char *[])
>> > {
>> > test_suite *test = BOOST_TEST_SUITE("Master test suite");
>> > test->add(BOOST_TEST_CASE(&JacobiTest1));
>> > return test;
>> > }
>> >
>> > Now I use
>> >
>> > * Additional autoconf code to define HAVE_UNIT_TEST_LIB if the
>> > (shared?)
>> > library is
>> > used.
>> >
>> > #ifdef HAVE_CONFIG_H
>> > #include <config.h> // HAVE_UNIT_TEST_LIB
>> > #endif
>> >
>> > #ifdef HAVE_UNIT_TEST_LIB
>> > # define BOOST_TEST_DYN_LINK
>> > # include <boost/test/unit_test.hpp>
>> > #else
>> > # include <boost/test/included/unit_test.hpp>
>> > #endif
>>
>> 1. You can use static library and no need to define BOOST_TEST_DYN_LINK
>> for
>> either library of included variant
>> 2. You can use included variant always
>> 3. You can switch to automated registration and you don't need to define
>> nor
>> function main(), nor init function
>
>> If you insist on combination of manual registration with shared library,
>> it
>> should look like this:
>>
>> int
>> main( int argc, char* argv[] )
>> {
>> return ::boost::unit_test::unit_test_main( &init_unit_test, argc,
>> argv );
>> }
>
> Without changing the registration to use
> framework::master_test_suite()->add(Jacobi_test_suite())
> I would still get:
> Test setup error: test tree is empty

I am not sure I am following. You do need to register your test units.

>> If you can express it all better I am open to sugestions. It is indeed
>> not
>> very trivial (considering many different usage variant of Boost.Test) to
>> describe all necessary information and be both complete and easily
>> accessible to first timers.
>
> I suggest to simple reduce many different usage variants of Boost.Test!
> Let the user always specify main(), remove the init_unit_test parameter
> together with most of the macros as BOOST_TEST_DYN_LINK,
> BOOST_TEST_MAIN, BOOST_TEST_ALTERNATIVE_INIT_API, ...
> This will result in only two or three lines more of code but will be

In most cases it's more than that. And many people are not willing to
sacrify that. There is also the notion of init function and you will still
need BOOST_TEST_MAIN. In addition the change wouldn't be backward
compartible and many people will not be happy.

Gennadiy


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk