Boost logo

Boost :

From: Fernando Cacciola (fcacciola_at_[hidden])
Date: 2001-12-21 13:27:39


----- Original Message -----
From: rogeeff <rogeeff_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Friday, December 21, 2001 3:03 PM
Subject: [boost] Re: Unit Test Framework: Class Test Cases

> --- In boost_at_y..., "Fernando Cacciola" <fcacciola_at_g...> wrote:
> > > > This should be properly documented.
> > >
> > > >From the documentation:
> > >
> > > "The class_test_case is responsible for the creation and the
> > > destroying of the user's test class instance. It's recommended to
> use
> > > the class_test_case *only* if you can't implement a test logic in
> a
> > > free function."
> > >
> > I see.
> > Then this paragraph should be referenced in
>
> Sorry. I did not get. Where?
>
Oops!
Just two lines below :-)

Seriously, I just missed it when I read the doc. So never mind...

> [...]
>
> > > In reality usage of class_test_case is limited to the situations
> > > where you for any reason need to share information between test
> > > cases. The instance of user class is just a storage for this
> > > information. As an example let say you are testing very heavy
> class
> > > A. So you have test_construction test case and test_access test
> case.
> > > You could want to use preconstructed object in a test_access and
> > > construct it in test_construction.
> > >
> > Could you give a concrete example?
>
>
> struct test_A {
> A a;
> void test_constructor() {
> a.add( part );
> a.add( part );
> a.add( part );
>
> // validate a is properly constructed
> }
>
> void test_access() {
> BOOST_CHECK_EQUAL( a.get( key ), value );
> ...
> }
> }
>
OK.

>
>
> [...]
>
> > >
> > The problem is that I need to transfer information from the command
> line
> > into the test case.
> > How can I do that with a free function?
> >
> > (of course I could use gobal static data, but I was hoping that no
> to be
> > necessary)
>
> Good catch. Right away you should be able to use an extention and
> bind needed argument to the free function with arguments, like this
>
> void foo( char const* arg )
> {
> ...
> }
>
> test->add( BOOST_TEST_CASE( boost::bind( foo, _1, argv[2] );
>
> Hopefully bind will take care about lifetime of arguments. Is it,
> Piter?
>
> Though the problem seems to be pretty generic and worth adding to the
> base implementation. I could add an ability for the user to specify a
> ninstance of user test case as an optional argument to
> BOOST_TEST_CASE like this:
>
> BOOST_TEST_CASE(( &A::foo )); // here framework will create an
> instance
>
> A* a = new A(...)
> BOOST_TEST_CASE(( &A::foo, a )); // here framework will use the
> instance provided and DESTROY it at the end.
>
> How about this?
>
Yes, this is exactly what I would like to have.

BTW, I already add that to my copy.

In order to allow A not to need a default constructor that is probably never
used I added to unit_test_suite.hpp:

template<class UserTestCase>
struct fixed_user_test_case_holder : public test_case {
    // Constructor / Destructor

    fixed_user_test_case_holder( UserTestCase* a_user_test_case )
       : m_user_test_case( a_user_test_case ) {}

    ~fixed_user_test_case_holder() {}

    void init () {}
    void destroy() {}

    UserTestCase* m_user_test_case;
};

!!!!!!! NOTE: init() and destroy() are no-ops (that's why I originaly asked
about them).

template<class UserTestCase>
class fixed_class_test_case : public test_case {
public:
    typedef void (UserTestCase::*function_type)();

    // Constructor
    fixed_class_test_case( UserTestCase* ins, function_type f, char const*
name )
    : test_case( name, 1 ), m_holder(ins), m_function( f ) {}

private:
    // test case implementation
    void do_init() { m_holder.init(); }
    void do_run()
 (m_holder.m_user_test_case->*m_function)(); }
    void do_destroy() { m_holder.destroy(); }

    // Data members
    fixed_user_test_case_holder<UserTestCase> m_holder;
    function_type m_function;
};

And also a 'closure' class so the BOOST_TEST_CASE() macro can remain the
same (and just call):

template<class ClosureType>
inline test_case*
create_test_case( ClosureType const& a_closure , std::string name )
{
  typedef typename ClosureType::class_type UserTestCase ;

  return new fixed_class_test_case<UserTestCase>( a_closure.m_obj,
                                                  a_closure.m_func,

detail::normalize_test_case_name( name )
                                                );
}

But the 'closure' class might be tricky to get right, so if

> BOOST_TEST_CASE(( &A::foo, a )); // here framework will use the

can be parsed correctly it is probably better.

Fernando Cacciola
Sierra s.r.l.
fcacciola_at_[hidden]
www.gosierra.com


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