Download | News | Support | Project |
This section introduces most of the library features in a series of use cases built on the example from the motivation section.
For all the code examples the following is assumed :
#include <turtle/mock.hpp> #include <boost/test/unit_test.hpp>
A simple unit test with mock objects usually splits into several phases as illustrated by :
BOOST_AUTO_TEST_CASE(zero_plus_zero_is_zero) { mock_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 signalled if any unfulfilled expectation remains.
More sophisticated tests sometimes require more complex use cases and in particular might need to verify or reset mock objects.
Here is an example highlighting the different possibilities :
BOOST_AUTO_TEST_CASE(zero_plus_zero_is_zero_reset) { mock_view v; calculator c(v); MOCK_EXPECT(v.display).once().with(0); c.add(0, 0); MOCK_VERIFY(v.display); // verify all expectations are fulfilled for the 'display' method mock::verify(v); // verify all expectations are fulfilled for all methods of 'v' mock::verify(); // verify all expectations are fulfilled for all existing mock objects MOCK_RESET(v.display); // reset all expectations for the 'display' method mock::reset(v); // reset all expectations for all methods of 'v' mock::reset(); // reset all expectations for all existing mock objects } // automatically verify all expectations are fulfilled for all mock objects going out of scope
Note that all verifications upon destruction will be disabled if the mock objects are destroyed in the context of an exception being raised.
A method can be configured with several expectations, for instance :
BOOST_AUTO_TEST_CASE(zero_plus_zero_is_zero_expect) { mock_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 processing the expectations in the order they have been defined :
An error is raised if none can be found.
By default the relative order of the calls does not matter. It can however be enforced :
BOOST_AUTO_TEST_CASE(zero_plus_zero_is_zero_then_1_plus_0_is_1) { mock_view v; calculator c(v); mock::sequence s; MOCK_EXPECT(v.display).once().with(0).in(s); // add this expectation to the sequence MOCK_EXPECT(v.display).with(1).in(s); // add this expectation to the sequence after the previous call c.add(0, 0); c.add(1, 0); }
Therefore an error will be issued if the second expectation is matched before the first one has been exhausted.
An expectation can be part of several sequences :
BOOST_AUTO_TEST_CASE(add_several_numbers_in_sequences) { mock_view v; calculator c(v); mock::sequence s1, s2; MOCK_EXPECT(v.display).once().with(0).in(s1); MOCK_EXPECT(v.display).once().with(1).in(s2); MOCK_EXPECT(v.display).with(2).in(s1, s2); // add this expectation to both sequences after the previous calls c.add(0, 0); c.add(1, 0); c.add(1, 1); c.add(2, 0); }
During the execution of a test case, an error can happen for one of the following reasons :
The exact type of the exception thrown depends on the test framework integration used.
An error log typically looks like :
unknown location(0): error in "zero_plus_zero_is_zero": unexpected call: v.mock_view::display( 0 ) v once().with( 1 ) v once().with( 2 ) . once().with( 3 )
On the first line is the description of what happened : here the display method of object v of class mock_view has been called with an actual value of 0.
The following lines list the set expectations with the check (the v character) meaning the expectation has been exhausted. It therefore means that the two first expectations have been fulfilled by two calls, and then instead of 3 in the third call 0 has been erroneously passed on to the mock object.
Another common error looks like :
src/tests/turtle_test/Tutorial.cpp(73): error in "zero_plus_zero_is_zero": untriggered expectation: v.mock_view::display v once().with( 1 ) v once().with( 2 ) . once().with( 3 )
The first line tells that a set expectation has not been fulfilled. The file and line number give the location where the corresponding expectation has been configured.
The following lines once again list the set expectations. It means the two first calls correctly passed the expected values to the mock object, but then no third call happened.
Finally an error looking like :
src/tests/turtle_test/Tutorial.cpp(73): error in "zero_plus_zero_is_zero": missing action: v.mock_view::display( 0 ) v once().with( 0 )
indicates that an action is missing because a mock function must be told what to do when called if it has a return type other than void, for instance given :
class view { public: virtual bool display(int result) = 0; // returns a boolean };
the following test case will raise a missing action error :
BOOST_AUTO_TEST_CASE(zero_plus_zero_is_zero_with_action) { mock_view v; calculator c(v); MOCK_EXPECT(v.display).once().with(0); // missing returns( true ) c.add(0, 0); }