RudeMocks/Setting Up Expectations
From Wiki
Contents |
Table of Contents
- RudeMocks/Introduction
- RudeMocks/Basic Usage
- RudeMocks/Mocking Classes
- RudeMocks/Mocking Free Functions
- RudeMocks/Setting Up Expectations
- RudeMocks/Out and In-Out Arguments
- RudeMocks/Returning Non-Default Constructible Objects
- RudeMocks/Ordered and Unordered Expectation Recording
- RudeMocks/Ignoring Unexpected Calls
Per-Function Options
ExpectCall and Return
In RudeMocks, expectations are set up by simply calling the function with expected arguments. For functions that have return values the call must be wrapped in ExpectCall(<function call>).Return(<expected return value>) as was shown in previous sections. Here's an example:
// we have two free functions somewhere int MyFunctionThatReturnsSomething(int x, double y) { return 5; } void MyFunctionThatReturnsNothing(int x, double y) {} ... // create a mock repository MockRepository mocks; RegisterFunctions(mocks.CreateFreeFunctionMock(), &MyFunctionThatReturnsSomething, &MyFunctionThatReturnsNothing); // set up expectations for the free functions ExpectCall(MyFunctionThatReturnsSomething(4, 10.0)).Return(5); MyFunctionThatReturnsNothing(4, 10.0); // no need for ExpectCall since the function returns void
In addition to ExpectCall RudeMocks offers a number of additional per-function call and per-argument options that can be used when setting up expectations. These additional options are accessed by chaining special function calls to ExpectCall() or LastCall() as described in the next section. Note that when using additional options with ExpectCall() function options must come before per-argument options!
Ignoring Arguments and LastCall
By default, RudeMocks verifies all arguments passed to a function when setting up expectations during recording. So when the mocks are in replay mode and the actual code under test is executed, RudeMocks will compare the actual function arguments with the expected function arguments that were passed to the function while in record mode. However, it is possible to ignore argument verification of all arguments or only certain arguments of a function.
To ignore all arguments the IgnoreArguments option is used like this:
ExpectCall(MyFunctionThatReturnsSomething(0, 0.0)).Return(5).IgnoreArguments(); MyFunctionThatReturnsNothing(400, 8.0); LastCall().IgnoreArguments();
Note that it doesn't matter what argument values are passed to the functions. As long as they have the correct type, they could be anything. RudeMocks will not use these values to perform argument verification when in replay mode. They will simply be ignored. So expectations that ignore all arguments are expectations that only make sure a particular function is called, but it doesn't matter with what argument values.
Also note how IgnoreArguments is called for MyFunctionThatReturnsNothing. For functions that return void ExpectCall() cannot be used. LastCall() must be used instead and it must follow immediately after the function call to which it applies. As the name implies LastCall() always affects the last set up expectation.
In order to ignore only certain arguments but verify others a reference to the argument options of a specific argument must first be retrieved. This is done by calling the Arg() function, again chaining it to either ExpectCall() or LastCall().
ExpectCall(MyFunctionThatReturnsSomething(0, 5.0)).Return(5).Arg(0).Ignore(); MyFunctionThatReturnsNothing(10, 8.0); LastCall().Arg(1).Ignore();
In the above example, RudeMocks will only ignore the first argument of the first free function, but verify that the double argument is indeed 5.0. Similarly, only the second argument of the second free function will be ignored and the first argument must match the given value of 10.
Throw
If a function should throw an exception instead of returning a value you can use the Throw() function option instead of Return(). The passed in exception object (which can be of arbitrary type) is stored internally and thrown during replay if the function is verified successfully, i.e. if argument verification succeeded.
ExpectCall(MyFunctionThatReturnsSomething(0, 5.0)).Throw(std::exception()); mocks.Replay(); MyFunctionThatReturnsSomething(0, 5.0); // will throw std::exception
Repeat, Once, and Twice
In RudeMocks it is possible to easily set up multiple, expected function calls using the Repeat(min, max) function option, or its convenient counterparts Once() and Twice(). Repeat() accepts the minimum and the maximum allowed call count of the function as arguments. Verification succeeds if the function was called at least the minimum number of times and at most the maximum number of times specified during recording. Here's an example:
ExpectCall(CallThisOften(5, 10.0)).Return(10).Repeat(2, 5); CallThisOnlyOnce(100); LastCall().Once(); // could also just be: CallThisOnlyOnce(100); CallThisTwice(200, 300); LastCall().Twice();
This expectation means that the function CallThisOften needs to be called at least 2 times and at most 5 times with the given arguments (5, 10.0) to be verified successfully. Once() means that the function must be called exactly once. It is more or less redundant since you can just call the function to achieve the same effect. It is mostly for emphasis and documentation purposes. It is equivalent to calling Repeat(1, 1). Similarly, Twice() means that the function must be called exactly two times. It is equivalent to Repeat(2, 2).
Never
Sometimes it is important in a test to verify that a function was never called. The Never() function option fulfills exactly this purpose. If the function is called nevertheless during replay the verification fails. Note that unless IgnoreArguments() or Ignore() are used the arguments will still be taken into consideration. So in the following example, the first expectation means that the function should never be called with 1000 as argument value. However, calling it with, say, 2000 is just fine (assuming another expectation has been set up for that case). The second expectation with IgnoreArguments() means that the function must never be called. Verification fails if it is ever called, irrespective of what arguments are passed to it.
NeverCallWith1000(1000); LastCall().Never(); DontCallUsWellCallYou(5, 10, "boooh"); LastCall().IgnoreArguments().Never();
Do
The most flexible function option is Do(). It allows you to specify a boost::function of type
boost::function<ReturnType ( const boost::shared_ptr<const ExpectationBase>& expectation, const boost::shared_ptr<const FunctionArgumentsBase>& actualFunctionArguments)>
where ReturnType is the return type of the function or void if the function returns nothing.
Do() should not be used together with Return(). Also, just like Return(), it must be used before any per-argument options.
Here's an example of how Do() can be used to return a custom, computed return value from a mocked function:
int FunctionThatReturnsInt(int x) { return x; } struct ReturnValueFunction { int operator () (const boost::shared_ptr<const ExpectationBase>& expectation, const boost::shared_ptr<const FunctionArgumentsBase>& actualFunctionArguments) const { // cast the function argument object down to the correct type boost::shared_ptr<const FunctionArguments<boost::fusion::vector<int> > > functionArguments = boost::dynamic_pointer_cast<const FunctionArguments<boost::fusion::vector<int> > >(actualFunctionArguments); // return a custom return value return functionArguments->GetArgument<0>() + 4; } }; ExpectCall(FunctionThatReturnsInt(3)).Do(ReturnValueFunction());
When this expectation is replayed it will call operator () of ReturnValueFunction, which in turn will return 4 plus the value of the first argument, which in this case is 3, so 7 is the returned value.
Note that in the above example regular argument verification is still performed. However, in combination with IgnoreArguments() Do() allows you to customize the argument verification process and return a custom return value. Note that the argument option Do() is a better way of doing custom verification though. Basically Do() is meant as a more powerful Return(), i.e. it should be used to compute a complicated, argument-dependent return value. The technical reason for this is that the Do() function option is not called to check if verification of an actual function call _could_ succeed. This is required internally for ordered and unordered expectation recording.
int FunctionThatReturnsInt(int x) { return x; } struct ReturnValueFunction { int operator () (const boost::shared_ptr<const ExpectationBase>& expectation, const boost::shared_ptr<const FunctionArgumentsBase>& actualFunctionArguments) const { // cast the function argument object down to the correct type boost::shared_ptr<const FunctionArguments<boost::fusion::vector<int> > > functionArguments = boost::dynamic_pointer_cast<const FunctionArguments<boost::fusion::vector<int> > >(actualFunctionArguments); // perform custom argument verification; you could grab the ExpectationFailureHandler from the mock repository // to better integrate with the framework, but here we just throw int argumentValue = functionArguments->GetArgument<0>; if (argumentValue < 5 || argumentValue > 10) throw std::exception("Argument value is out of range."); // return a custom return value return 6; } }; ExpectCall(FunctionThatReturnsInt(3)).IgnoreArguments().Do(ReturnValueFunction());
Per-Argument Options
Per-argument options are accessed by calling Arg(index), OutArg(index), or InOutArg(index) where index is the 0-based argument index. Note that for technical reasons the function options Return() and Do() must always come before any argument options.
For more information on out and in-out arguments see here.
Ignore
We've already seen the Ignore() option above when discussing the IgnoreArguments() per-function option. Ignore() causes the argument it is called for to be ignored during argument verification. The specified expected value when setting up the expectation is irrelevant and disregarded. It only needs to be there so that the code compiles. Here's an example where the first argument of the function will be ignored:
MyFunctionThatReturnsNothing(10, 8.0); LastCall().Arg(1).Ignore(); // it doesn't matter that we specified 8.0 above; that expected value will be ignored mocks.Replay(); MyFunctionThatReturnsNothing(10, 100.0); // verifies fine; 10 was expected, 100.0 is ignored MyFunctionThatReturnsNothing(9, 100.0); // fails verification; 9 is unexpected, 100.0 is ignored
IsEqual and IsNotEqual
Two other very useful per-argument options are IsEqual() and IsNotEqual(). As their names imply they verify that the actual argument value either matches or does not match an expected, recorded value. IsEqual is the default argument verifier, so if you simply use ExpectCall() or call a void function IsEqual is used for all arguments of the function. However, as shown previously, with IgnoreArguments() you can turn off argument verification for all arguments. In some cases, you might want to turn it on for a partciular argument and that's exactly what you can do with IsEqual:
// ignore all arguments, but not the second one, which needs to be equal ExpectCall(mock, MyFunctionThatReturnsSomething(0, 5.0)).Return(5).IgnoreArguments().Arg(1).IsEqual(); // make sure the first argument is not equal to 10 and ignore the second one MyFunctionThatReturnsNothing(10, 8.0); LastCall().Arg(0).IsNotEqual().Arg(1).Ignore()
IsEqual() and IsNotEqual() optionally accept an expected value that is used instead of the one specified when calling the function. This might be convenient in some cases and makes the code somewhat clearer to read if you use IgnoreArguments(). Here's an example:
// ignore all arguments, but not the second one, which needs to be equal to 5.0; note that the original expected value was 0.0 but it will not be used ExpectCall(mock, MyFunctionThatReturnsSomething(0, 0.0)).Return(5).IgnoreArguments().Arg(1).IsEqual(5.0);
Depending on what a given argument type supports IsEqual() will try to use operator == or a simple memcmp to check for equality. Similarly, IsNotEqual will use operator !=, if available, or fall back to doing !(operator ==), if operator == is available, and finally falll back to !memcmp.
IsLessThan et al
RudeMocks offers per-argument options for all comparison operators. Apart from IsEqual() and IsNotEqual() there are IsLessThan(), IsLessThanOrEqual(), IsGreaterThan(), and IsGreaterThanOrEqual(). Similar to IsEqual() they optionally accept an expected value as argument. If not provided, it will use the value that was initially passed to the function when setting up the expectation. All of these options will fail if the argument type does not support operator <, <=, >, and >=, respectively.
Do
Do() for arguments works in a similar way as Do() for the entire function. It allows you to specify a custom argument verifier function that will be called whenever the argument needs to be verified. The function needs to have a very special signature depending on the type of the argument that is stored internally by an expectation. Here's the signature the custom argument verifier function needs to have for an argument type T, which could be any class type, fundamental type, reference or pointer type:
boost::function<bool (std::size_t argumentIndex, ArgumentValue<T> expectedValue, ArgumentValue<T> actualValue, std::string& description)>
The function must return a bool indicating whether verification succeeded or not. It receives the 0-based argument index, expected value, and actual value of the argument under verification. The values are encapsulated in the ArgumentValue template. The function can also return a description string in the case of verification failure that more closely describes why verification failed. The type CustomArgumentVerifier<T>::Function is a typedef for the above Boost.Function function type.
The ArgumentValue template class only has one member function for parameters that are not out parameters and that is GetValue(). It returns a value of type T, i.e. of the argument type of the function.
Note that for out and in-out parameters Do() can modify the given actual argument value and return an arbitrary out value to the caller during replay. This allows computing out values on the fly in the verifier instead of using the OutArg(index).Return(value) syntax. This is done by calling ArgumentValue::SetOutValue() and is described in more detail here.
Here's an example:
void MyTestFunction(int, float); // A custom argument verifier function object that returns true when the actual value // is a multiple of the expected value. struct VerifyIntIsMultipleOf { bool operator () (std::size_t argumentIndex, ArgumentValue<int> expectedValue, ArgumentValue<int> actualValue, std::string& description) const { bool succeeds = (actualValue.GetValue() % expectedValue.GetValue()) == 0; if (!succeeds) { std::stringstream error; error << "Actual value " << actualValue.GetValue() << " is not a multiple of expected value " << expectedValue.GetValue() << '.'; description = error.str(); } return succeeds; } }; // Create the custom argument verifier function. VerifyIntIsMultipleOf verifierFunctionObject; CustomArgumentVerifier<int>::Function customVerifier(verifierFunctionObject); // Set up the expectation with custom argument verification. MyTestFunction(500, 10.0); LastCall().Twice().Arg(0).Do(customVerifier); mocks.Replay(); // Verifies fine. 1000 is 2 * 500, i.e. a multiple of 500, and 10.0 is the expected // value for the second argument. MyTestFunction(1000, 10.0); // Doesn't verify because 800 is not a multiple of 500. MyTestFunction(800, 10.0);