Turtle
From turtle
A C++ Mock_object library based on Boost with a focus on usability and simplicity.
|
Motivation
Consider a (very) simple calculator with this interface :
class calculator
{
public:
int add( int a, int b );
};
Obviously writing unit tests for such a class is trivial, one of them could be :
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
{
calculator c;
BOOST_CHECK_EQUAL( 0, c.add( 0, 0 ) );
}
What now if the calculator interface looks more like this :
class view
{
public:
virtual void display( int result ) = 0;
};
class calculator
{
public:
explicit calculator( view& v );
void add( int a, int b ); // the result will be sent to the view 'v'
};
Writing unit tests becomes a bit more tedious and requires some boiler-plate code :
class my_view : public view
{
public:
my_view()
: called( false )
{}
virtual void display( int result )
{
value = result;
}
bool called;
int value;
};
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
{
my_view v;
calculator c( v );
c.add( 0, 0 );
BOOST_REQUIRE( v.called );
BOOST_CHECK_EQUAL( 0, v.value );
}
Mock objects main purpose is to alleviate the user from the burden of writing all this boiler-plate code.
Here is how the last test can be rewritten using a mock object :
MOCK_BASE_CLASS( my_view, view ) // defines a 'my_view' class implementing 'view'
{
MOCK_METHOD( display, 1 ) // implements the 'display' method from 'view' (taking 1 argument)
};
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
{
my_view v;
calculator c( v );
MOCK_EXPECT( v, display ).once().with( 0 ); // expects the 'display' method to be called once (and only once) with a parameter value equal to 0
c.add( 0, 0 );
}
And all the checks are handled by the library.
Tutorial
This section introduces most of the library features in a series of use cases built on the example from the motivation section.
Create, expect, trigger, verify
A simple unit test with mock objects usually splits into several phases as illustrated by :
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
{
my_view v; // create mock objects
calculator c( v ); // create object under test
MOCK_EXPECT( v, display ).once().with( 0 ); // configure mock objects
c.add( 0, 0 ); // exercise object under test
} // verify mock objects
Triggering the object under test in turn calls methods on the mock objects, and any unexpected call raises an error.
Mock objects are automatically verified during their destruction and an error is signaled if any unfulfilled expectation remains.
More sophisticated tests sometimes require more complex use cases and in particular might need to :
- manually verify mock objects
- manually reset mock objects
Here is an example highlighting the different possibilities therefor :
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
{
my_view v;
calculator c( v );
MOCK_EXPECT( v, display ).once().with( 0 );
c.add( 0, 0 );
MOCK_VERIFY( v, display ); // verifies all expectations are fulfilled for the 'display' method
v.verify(); // verifies all expectations are fulfilled for all methods of 'v'
mock::verify(); // verifies all expectations are fulfilled for all existing mock objects
MOCK_RESET( v, display ); // resets all expectations for the 'display' method
v.reset(); // resets all expectations for all methods of 'v'
mock::reset(); // resets all expectations for all existing mock objects
} // automatically verifies all expectations are fulfilled for all mock objects going out of scope in their destructors
Note that all verifications upon destruction will be disabled if the mock objects are destroyed in the context of an exception being raised.
Matcher selection algorithm
A method can be configured with several expectations, for instance :
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
{
my_view v;
calculator c( v );
MOCK_EXPECT( v, display ).once().with( 0 ); // this call must occur once (and only once)
MOCK_EXPECT( v, display ).with( 1 ); // this call can occur any number of times (including never)
c.add( 0, 0 );
}
Each method call is then handled by :
- looking for a match with valid parameter constraints
- checking that the invocation count for this match is not exhausted
An error is raised if none can be found.
By default the order of the expectations does not matter. It can however be enforced if needed, for instance :
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
{
my_view v;
calculator c( v );
mock::sequence s;
MOCK_EXPECT( v, display ).once().with( 0 ).in( s ); // adds this expectation to the sequence
MOCK_EXPECT( v, display ).with( 1 ).in( s ); // adds this expectation to the sequence after the previous one
c.add( 0, 0 );
}
Therefore an error will be issued if the second expectation is matched before the first one has been exhausted.
Error diagnostic
Reporting errors
During the execution of a test case, an error can happen for one of the following reasons :
- unexpected call when no match can be found for the given arguments (throws a mock::exception)
- unexpected call when the enforced call sequence has not been followed (throws a mock::exception)
- verification failure if a remaining match has not been fulfilled when manually calling verify() (logs an error)
- untriggered expectation if a remaining match has not been fulfilled when destroying the mock object (logs an error)
- missing result specification if a method supposed to return something else than void has not been configured properly (throws a mock::exception)
By design mock::exception does not inherit from std::exception, for instance consider the following test case :
BOOST_AUTO_TEST_CASE( overflow_throws )
{
my_view v;
calculator c( v );
BOOST_CHECK_THROW( c.add( std::numeric_limits< int >::max(), 1 ), std::exception );
}
Any call to 'v' will be unexpected and yield an exception, which if it derived from std::exception would erroneously make the test succeed.
Logging customisation
In order to log a meaningful diagnostic of the failures, the library detects if a parameter type is serializable in a std::ostream and then uses this textual representation, otherwise the value is replaced with a '?'.
To override this behaviour the easiest means is either to provide a specialized version of the mock::format function, for instance :
namespace mock
{
template<>
inline std::string format<>( const some_type& t )
{
// ...
}
}
Or to provide an overload function :
namespace mock
{
inline std::string format( const some_type& t )
{
// ...
}
}
Labelling objects
When a test case involves several instances of the same type of mock objects it may be difficult to debug which one triggers an error.
For such cases it is possible to tag an object with an additional textual information, for instance :
BOOST_AUTO_TEST_CASE( some_test )
{
my_view v;
v.tag( "_1" );
}
The tag (here _1) will be appended to the type name (here my_view) for all logs. In this case it will show my_view_1.
Boost.Test integration
The only requirement when using Boost.Test is to include it before the mock library, for instance :
#include <boost/test/auto_unit_test.hpp> #include <turtle/mock.hpp>
This allows the mock library to detect the test framework and to provide various specific implementations.
Reference
This section describes the library syntax exhaustively.
Creating a mock object
Mocking a class
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_CLASS( class_name )
{
MOCK_METHOD_EXT( method_name, number_of_method_arguments, signature, tag )
};
Example :
MOCK_CLASS( my_class )
{
MOCK_METHOD_EXT( my_method, 2, void( int, const std::string& ), my_tag )
};
Alternative without macros :
class my_class : public mock::object // publicly deriving from mock::object is optional but enables better error diagnostics
{
public:
MOCK_METHOD_EXT( my_method, 0, void(), my_method )
};
Mocking a base class
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_BASE_CLASS( class_name, base_class_name )
{
MOCK_METHOD( method_name, number_of_method_arguments )
MOCK_METHOD_EXT( method_name, number_of_method_arguments, signature, tag )
};
Example :
class my_base_class
{
virtual void my_method( int, const std::string& ) = 0;
};
MOCK_BASE_CLASS( my_class, my_base_class )
{
MOCK_METHOD( my_method, 2 ) // the tag defaults to the method name, e.g. here 'my_method'
MOCK_METHOD_EXT( my_method, 2, void( int, const std::string& ), my_method ) // fails to compile as this is strictly identical to the previous declaration
MOCK_METHOD( my_non_existing_method, 0 ) // fails to compile as 'my_non_existing_method' does not exist in 'my_base_class'
};
Mocking a template base class
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
template< typename T >
MOCK_BASE_CLASS( class_name, base_class_name< T > )
{
MOCK_METHOD_TPL( method_name, number_of_method_arguments )
MOCK_METHOD_EXT_TPL( method_name, number_of_method_arguments, signature, tag )
};
Example :
template< typename T >
class my_base_class
{
virtual void my_method( T ) = 0;
virtual void my_other_method( T, int ) = 0;
};
template< typename T >
MOCK_BASE_CLASS( my_class, my_base_class< T > )
{
MOCK_METHOD_TPL( my_method, 1 ) // some compilers may not support this
MOCK_METHOD_EXT_TPL( my_other_method, 2, void( T, int ), my_other_method ) // this is supported by all compilers
};
Mocking a functor
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_FUNCTOR( signature ) instance;
Example :
MOCK_FUNCTOR( void( int ) ) my_functor; // instanciates a mock functor
Disambiguating methods
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_BASE_CLASS( class_name, interface_name )
{
MOCK_METHOD_EXT( method_name, number_of_method_arguments, signature, tag )
MOCK_CONST_METHOD_EXT( method_name, number_of_method_arguments, signature, tag )
MOCK_NON_CONST_METHOD_EXT( method_name, number_of_method_arguments, signature, tag )
};
Example :
class my_interface
{
virtual void my_method( int, const std::string& ) = 0;
virtual void my_method( float ) = 0;
virtual void my_method( float ) const = 0;
};
MOCK_BASE_CLASS( my_class, my_interface )
{
MOCK_METHOD_EXT( my_method, 2, void( int, const std::string& ), my_tag1 ) // generates both const and non-const methods treating them as one expectation, which is usually fine for most use cases
MOCK_CONST_METHOD_EXT( my_method, 1, void( float ), my_tag2 )
MOCK_NON_CONST_METHOD_EXT( my_method, 1, void( float ), my_tag3 )
};
class my_interface
{
virtual void my_method( float ) = 0;
virtual void my_method( float ) const = 0;
};
MOCK_BASE_CLASS( my_class, my_interface )
{
MOCK_METHOD( my_method, 1 ) // generates both const and non-const methods treating them as one expectation, which is usually fine for most use cases
};
Mocking a destructor
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_CLASS( class_name, interface_name )
{
MOCK_DESTRUCTOR( class_name, tag )
};
Example :
MOCK_CLASS( my_class ) // works with MOCK_BASE_CLASS too
{
MOCK_DESTRUCTOR( my_class, my_tag )
};
Configuring a mock object
Setting up an invocation
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_EXPECT( mock_object, tag ).invocation( arguments );
Example :
MOCK_CLASS( my_class )
{
MOCK_METHOD_EXT( my_method, 2, void( int, const std::string& ), my_method )
};
my_class c; MOCK_EXPECT( c, my_method ).once(); MOCK_EXPECT( c, my_method ); // can be called an unlimited number of times MOCK_EXPECT( &c, my_method ); // also accepts a pointer as first argument (as well as an std::auto_ptr or a boost::shared_ptr)
Example:
MOCK_FUNCTOR( void( int, const std::string& ) ) my_functor; MOCK_EXPECT( my_functor, _ ); // the tag is always _ for a mock functor
Available invocations :
- once()
- never()
- exactly( count )
- at_least( min )
- at_most( max )
- between( min, max )
Adding constraints
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_EXPECT( mock_object, tag ).with( parameter1_constraint, parameter2_constraint, ... );
Example :
MOCK_CLASS( my_class )
{
MOCK_METHOD_EXT( my_method, 2, void( int, const std::string& ), my_method )
};
my_class c; MOCK_EXPECT( c, my_method ).with( mock::equal( 3 ), mock::equal( "some string" ) ); MOCK_EXPECT( c, my_method ).with( 3, "some string" ); // equivalent to the previous one using shortcuts
Available constraints :
| mock::any | true |
| mock::equal( expected ) or expected (see below) | actual == expected |
| mock::less( expected ) | actual < expected |
| mock::greater( expected ) | actual > expected |
| mock::less_equal( expected ) | actual <= expected |
| mock::greater_equal( expected ) | actual >= expected |
| mock::constraint( expected ) or expected (see below) | expected( actual ) |
| mock::same( expected ) | &actual == &expected |
| mock::assign( expected ) | actual = expected, true |
| mock::retrieve( expected ) | expected = actual, true or expected = &actual, true |
| mock::negate | !actual |
| mock::evaluate | actual() |
| mock::call( expected ) | custom functor, e.g. expected( actual ) || any |
| floating point constraints | see Comparing floating point numbers and Boost.Math's float_distance |
| mock::is_a | dynamic_cast |
| mock::start_with, mock::end_with, mock::contain, mock::match (regex) | |
| mock::_ | shortcut for any() |
| mock::copy | for tabs and containers ? |
| mock::apply | for STL algorithms somehow ? |
When passing expected directly as a shortcut :
- mock::constraint is implied for :
- a function
- a function pointer
- an instance of a type with a result_type member typedef (support for standard library, Boost.Bind, Boost.Function functors)
- an instance of a type with a sig struct member (support for Boost.Lambda functors)
- mock::equal is implied for anything else
Here are a few examples, first using a function pointer :
namespace
{
bool f( int actual ) { return actual == 42; }
}
...
MOCK_EXPECT( c, my_method ).with( &f );
Using a standard library functor :
namespace
{
bool f( int expected, int actual ) { return expected == actual; }
}
...
MOCK_EXPECT( c, my_method ).with( std::bind1st( std::ptr_fun( &f ), 42 ) );
Using Boost.Bind :
namespace
{
bool f( int expected, int actual ) { return expected == actual; }
}
...
MOCK_EXPECT( c, my_method ).with( boost::bind( &f, 42, _1 ) ) );
Using Boost.Lambda :
MOCK_EXPECT( c, my_method ).with( _1 == 42 );
Combining constraints using &&, || and ! :
my_class c; MOCK_EXPECT( c, my_method ).with( mock::less( 4 ) && mock::greater( 2 ), ! mock::equal( "" ) );
Enforcing expectations order
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
mock::sequence s; MOCK_EXPECT( mock_object1, tag1 ).in( s ); MOCK_EXPECT( mock_object2, tag2 ).in( s );
Example :
MOCK_CLASS( my_class1 )
{
MOCK_METHOD_EXT( my_method1, 0, void(), my_method1 )
};
MOCK_CLASS( my_class2 )
{
MOCK_METHOD_EXT( my_method2, 0, void(), my_method2 )
};
my_class1 c1; my_class2 c2; mock::sequence s; MOCK_EXPECT( c1, my_method1 ).in( s ); MOCK_EXPECT( c2, my_method2 ).in( s );
Several sequences can be set by chaining calls to in.
Example :
my_class1 c1; mock::sequence s1, s2; MOCK_EXPECT( c1, my_method1 ).in( s1 ).in( s2 );
Configuring results
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_EXPECT( mock_object, tag ).returns( value ); MOCK_EXPECT( mock_object, tag ).throws( exception ); MOCK_EXPECT( mock_object, tag ).calls( functor );
Example :
MOCK_CLASS( my_class )
{
MOCK_METHOD_EXT( my_method, 0, int( int ), my_method )
};
int my_function( int i )
{
return i;
}
my_class c; MOCK_EXPECT( c, my_method ).returns( 42 ); MOCK_EXPECT( c, my_method ).throws( std::runtime_error( "error !" ) ); MOCK_EXPECT( c, my_method ).calls( &my_function ); // forwards 'my_method' parameter to the functor MOCK_EXPECT( c, my_method ).calls( boost::bind( &my_function, 42 ) ); // drops 'my_method' parameter and binds 42 as parameter to the functor
Summary
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_EXPECT( mock_object, tag ).invocation( arguments ).with( constraints ).in( sequence ).result( value );
Example:
MOCK_EXPECT( my_mock, my_method ).once().with( 0 ).returns( 42 ); MOCK_EXPECT( my_mock, my_method ).never().with( "ok", mock::any ); MOCK_EXPECT( my_mock, my_method ).at_least( 2 ).in( my_sequence ).throws( std::runtime_error() );
Verifying a mock object
Note that each mock object verifies itself upon destruction, which is sufficient for most use cases.
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_VERIFY( mock_object, tag );
Example :
MOCK_CLASS( my_class )
{
MOCK_METHOD_EXT( my_method, 0, void(), my_method )
};
my_class c; MOCK_EXPECT( c, my_method ).once(); c.my_method(); MOCK_VERIFY( c, my_method ); // logs an error and returns false if not all expectations are met MOCK_VERIFY( &c, my_method ); // also accepts a pointer as first argument (as well as an std::auto_ptr or a boost::shared_ptr)
Alternatively :
c.verify(); // verifies all expectations set for all methods of 'c'
Example:
MOCK_FUNCTOR( void( int ) ) my_functor; MOCK_EXPECT( my_functor, _ ).once(): my_functor( 42 ): MOCK_VERIFY( my_functor, _ );
Alternatively :
my_functor.verify(); // behaves exactly as the previous macro version
Also :
mock::verify(); // verifies all existing mock objects
Resetting a mock object
Prerequisite :
#include <turtle/mock.hpp>
Synopsis :
MOCK_RESET( mock_object, tag );
Example :
MOCK_CLASS( my_class )
{
MOCK_METHOD_EXT( my_method, 0, void(), my_method )
};
my_class c; MOCK_EXPECT( c, my_method ); MOCK_RESET( c, my_method ); MOCK_RESET( &c, my_method ); // also accepts a pointer as first argument
Alternatively :
c.reset(); // resets all expectations set on 'c'
Example :
MOCK_FUNCTOR( void( int ) ) my_functor; MOCK_EXPECT( my_functor, _ ); MOCK_RESET( my_functor, _ );
Alternatively :
my_functor.reset(); // behaves exactly as the previous macro version
Also :
mock::reset(); // resets all existing mock objects
Rationale
- main forces : writing tests quickly/easily and getting good diagnostic upon error (code error, mock error)
- intuitive => chainable syntax, constraints operators, no method to configure if not possible (e.g. returns() on expectation returning void, with() with correct #args, etc...), sensible shortcuts (with( value ), with( functor ), ...), automatic verification upon destruction, macros
- automatic type conversion => template, types kept as long as possible (limitation: literal 0 cannot be used for pointers), by reference transparently when implicit and boost::ref to override
- can be extended => custom constraints, can be combined, functors everywhere
- helpful => meaningful error diagnostic, automatic use of std::ostream operator << if available
- boost test integration => optional, transparently use Boost.Test features (exception, logging)
- why macros ?
- line number and file can be added for logging purpose (MOCK_EXPECT)
- packs a lot of code and hides implementation (MOCK_BASE_CLASS, MOCK_METHOD)
- makes interface uniform (MOCK_FUNCTOR, MOCK_CLASS)
- mock::exception does not inherit from std::exception to not give false test pass when the user tests for his code to throw exceptions
Patterns
This section presents ways to use the library out of the box.
Waiting for an asynchronous call
Problem :
namespace
{
class my_base_class
{
public:
virtual void my_method() = 0;
};
class my_class
{
public:
explicit my_class( my_base_class& );
void flush(); // repetitively calling this method will in turn call my_base_class::my_method at some point
};
}
Solution :
#include <turtle/mock.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/thread.hpp>
namespace
{
template< typename F >
void wait( bool& condition, F flush, int timeout = 100, int sleep = 100 )
{
while( !condition && timeout > 0 )
{
--timeout;
if( sleep > 0 )
boost::this_thread::sleep( boost::posix_time::milliseconds( sleep ) );
flush();
}
}
MOCK_BASE_CLASS( mock_base_class, my_base_class )
{
MOCK_METHOD( my_method, 0 )
};
}
BOOST_AUTO_TEST_CASE( my_method_is_called )
{
mock_base_class my_mock;
my_class my_instance( my_mock );
bool done = false;
MOCK_EXPECT( my_mock, my_method ).once().calls( boost::lambda::var( done ) = true );
wait( done, boost::bind( &my_class::flush, &my_instance ) );
}
mock::retrieve + mock::calls + boost::ref
Acknowledgments
Many thanks to Adrien Gervaise !
Limitations
- cannot use 0 as null pointer in expectation operator() calls
- cannot use 0 as null pointer in constraints, e.g. .with( mock::equal( 0 ) ) and even .with( 0 ) fail to compile => must use .with( mock::equal< type* >( 0 ) ) or .with( (type*)0 )
- missing result specifications are not detected at compile-time
- providing an equality operator to make types usable in mock::equal yields writing bool operator==( const T1& actual, const T2& expected ) which inverts the parameters compared to the usual 'expected' first and 'actual' second of testing frameworks
- MOCK_METHOD makes use of Boost.Typeof and hence inherits the same liabilities
- no support for std::wstring logging
- MOCK_CLASS and MOCK_BASE_CLASS cannot be used at function scope with some compilers
- cannot mock a template method (must create one mock class per type)
- warning C4505: 'my_base_class::[thunk]: __thiscall my_base_class::`vcall'{0,{flat}}' } : unreferenced local function has been removed
- see https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=324427
- => pragma warning disable
- warning C4301: '`anonymous-namespace'::my_base_class::f': overriding virtual function only differs from '`anonymous-namespace'::my_base_class::f' by const/volatile qualifier
- const copy parameter (base type or pointer)
- private pure virtual method cannot be mocked using MOCK_METHOD => use MOCK_METHOD_EXT
ToDo
- less strict constraint template compatibility
- custom constraints
- result handling
- several matchers on one expectation
- mock object contains expectations => verify/reset
- functions returning &
- no "returns" method on matcher< void( ... ) >
- error report
- customize error handling (error policy with default to throw)
- constraint1 &&/||/! constraint2 (and_ / or_ / not_)
- returns & on non-copyable class => boost::ref
- returns std::auto_ptr
- strict / enforce invocation order (sequence)
- retrieve non-const but & parameters / assign to pointer
- error handling : add actual parameters to log
- error handling : find a means to log non-serializable parameters/constraints
- private namespace 'detail'
- returns( 0 ) as null ptr
- with( 1 ) shortcut for with( equal( 1 ) )
- expects() shortcut for expects( mock::unlimited() )
- expects( 2 ) shortcut for expects( mock::exactly( 2 ) )
- n-matchers generation
- better support for std::auto_ptr as result (e.g. the 'factory' pattern)
- macros
- forward parameters to calls() user functor
- MOCK_EXPECT( object, Method ).once().with( data ).calls( functor )
- MOCK_OBJECT => MOCK_INTERFACE
- mock static polymorphism using MOCK_CLASS
- mock operators using MOCK_METHOD_EXT
- MOCK_MOCKER( ambassador, SubscribeClass ).reset() => MOCK_RESET( ambassador, SubscribeClass )
- expects => expect
- rename _mocker suffix to _exp (as in expectation)
- automatic verify upon destruction
- no_match or sequence_failed errors deactivate the automatic verification upon destruction
- mock::any() => mock::any, mock::negate() => mock::negate, mock::evaluate() => mock::evaluate
- only include necessary : #include <turtle/mock.hpp>
- find a means to accept .with( f ) with f function, function pointer, boost::bind, boost::function, etc.. as if it were a .with( mock::constraint( f ) )
- add sig template detection for mock::detail::is_functor see Boost.Lambda
- specialize mock::detail::format for std::string/const char* to surround them with "
- move mock::detail::format to mock::format
- use std::uncaught_exception() somehow to filter out verifications upon expectation destruction
- mock functors
- MOCK_INTERFACE => MOCK_BASE_CLASS
- mock methods with template class parameter(s)
- use Boost.Exception : throw boost::enable_current_exception( ... )
- MOCK_EXPECT support for std::auto_ptr and boost::shared_ptr
- mocking a destructor
- tag => id
- add file/line to missing_result_specification
- MOCK_METHOD_EXT => MOCK_???
- mock static methods (static polymorphism)
- error handling : better diagnostic when sequence fails (log all matchers involved in the sequence)
- boost concept check ? static assert ? shift user from long compilation error traces when possible
- remove from user reach primitives from matcher, sequence, etc.. (friend, using, proxies, etc..)
- usable without Boost.Test
- automatically detect Boost.Test inclusion and provide different implementations (macros, error_policy, etc..)
- mock template methods
- mocking a constructor
- stubbing a whole mock::object
- means to set a nice mock that doesn't fail when some unmatched expectations remain ?
- customize matcher find algorithm
- custom Allocator ?
- intercept function calls (see MockItNow) ?
- unicode support (mock::wexpectation, etc... typedef on common class templated on char/wchar_t)
- thread-safe expectations + MOCK_WAIT to sleep/wait with timeout until expectation satisfied
- e.expects( _1 <= 2 )
- a la Hippo Mocks, e.g. MyMock& m = make_mock< MyMock >()
- accept functors providing a description instead of std::string for mock::constraint
- add parameter to all constraints for customizing the description (std::string or functor)
- MOCK_CLASS* within a function/test case
- shouldn't reset implicitly call verify ?
- mock::format for STL types, e.g. std::vector, std::set, etc..
- grouping mock objects
- MOCK_VERIFY( o, _ ) for regular non functor mock objects
- Boost-ification
- namespace
- macros
- bjam build
- boostdoc
- layout
- guidelines
- #include <boost/config.hpp> ?
- add doc entry to explain what the error messages mean precisely
References
