Optional parameters in mocked method

6,055 views
Skip to first unread message

Michael Williamson

unread,
May 1, 2009, 5:05:31 AM5/1/09
to Google C++ Mocking Framework
Does google mock support optional parameters?
(I believe they're not allowed in google coding standards ...)

I'm mocking a 3rd party library class.
I use an "adapter" to wrap it, and am trying to keep the function signatures equivalent.

The original library method:
        virtual SceneNode* createChildSceneNode(
            const Vector3& translate = Vector3::ZERO,
            const Quaternion& rotate = Quaternion::IDENTITY );

My adapter equivalent:
        virtual SceneNodeAdapter* createChildSceneNode(
            const Ogre::Vector3& translate = Ogre::Vector3::ZERO,
            const Ogre::Quaternion& rotate = Ogre::Quaternion::IDENTITY ) = 0;

And I derive from the adapter to produce the mock:
        MOCK_METHOD2( createChildSceneNode, SceneNodeAdapter* (
            const Ogre::Vector3& translate = Ogre::Vector3::ZERO,
            const Ogre::Quaternion& rotate = Ogre::Quaternion::IDENTITY ) );

This last produces an error:
======
gmock-spec-builders.h(1325) : error C2383: 'F' : default-arguments are not allowed on this symbol
1>        c:\devroot\gmock-1.1.0\include\gmock\gmock-spec-builders.h(1325) : see reference to class template instantiation 'testing::internal::MockSpec<F>' being compiled
1>        with
1>        [
1>            F=OgreTestSeams::SceneNodeAdapter *(const Ogre::Vector3 &,const Ogre::Quaternion &)
======

If optional params are not supported by gmock, is a solution to make my adapter instead overload createChildSceneNode with 0, 1 and 2 argument versions?

Cheers,
Wally

Zhanyong Wan (λx.x x)

unread,
May 1, 2009, 12:38:29 PM5/1/09
to Michael Williamson, Google C++ Mocking Framework
Wally,

On Fri, May 1, 2009 at 2:05 AM, Michael Williamson <find...@gmail.com> wrote:
> Does google mock support optional parameters?
> (I believe they're not allowed in google coding standards ...)
>
> I'm mocking a 3rd party library class.
> I use an "adapter" to wrap it, and am trying to keep the function signatures
> equivalent.
>
> The original library method:
>         virtual SceneNode* createChildSceneNode(
>             const Vector3& translate = Vector3::ZERO,
>             const Quaternion& rotate = Quaternion::IDENTITY );
>
> My adapter equivalent:
>         virtual SceneNodeAdapter* createChildSceneNode(
>             const Ogre::Vector3& translate = Ogre::Vector3::ZERO,
>             const Ogre::Quaternion& rotate = Ogre::Quaternion::IDENTITY ) =
> 0;

Since *you* are writing the wrapper and *you* control the code using
the wrapper, you don't have to make your wrapper accept default
arguments just because the original method does. Is that an option?

If you really need default arguments for your mock method, you can do
it. I'll show you how below.

> And I derive from the adapter to produce the mock:
>         MOCK_METHOD2( createChildSceneNode, SceneNodeAdapter* (
>             const Ogre::Vector3& translate = Ogre::Vector3::ZERO,
>             const Ogre::Quaternion& rotate = Ogre::Quaternion::IDENTITY ) );
>
> This last produces an error:
> ======
> gmock-spec-builders.h(1325) : error C2383: 'F' : default-arguments are not
> allowed on this symbol
> 1>        c:\devroot\gmock-1.1.0\include\gmock\gmock-spec-builders.h(1325) :
> see reference to class template instantiation
> 'testing::internal::MockSpec<F>' being compiled
> 1>        with
> 1>        [
> 1>            F=OgreTestSeams::SceneNodeAdapter *(const Ogre::Vector3
> &,const Ogre::Quaternion &)
> ======
>
> If optional params are not supported by gmock, is a solution to make my
> adapter instead overload createChildSceneNode with 0, 1 and 2 argument
> versions?

The method itself shouldn't care about whether it was invoked with
default arguments or explicit arguments. Therefore using 3 overloaded
mock methods isn't a very good solution. It makes it harder to set
expectations on the method.

I suggest this pattern:

MOCK_METHOD2(createChildSceneNodeImpl, SceneNodeAdapter* (
const Ogre::Vector3& translate,
const Ogre::Quaternion& rotate) );


virtual SceneNodeAdapter* createChildSceneNode(
const Ogre::Vector3& translate = Ogre::Vector3::ZERO,

const Ogre::Quaternion& rotate = Ogre::Quaternion::IDENTITY ) {
return createChildSceneNodeImpl(translate, rotate);
}

Then, your production code will use createChildSceneNode() as usual.
In your tests you would write:

EXPECT_CALL(mock_foo, createChildSceneNodeImpl(_, _))...;

--
Zhanyong

Zhanyong Wan (λx.x x)

unread,
May 1, 2009, 5:22:33 PM5/1/09
to Michael Williamson, Google C++ Mocking Framework
Wally,

On second thought, I am not sure what you are trying to achieve.

Your mock class implements an interface, and createChildSceneNode() is
in that interface. Your production code talks to that interface. As
long as you specify the default arguments in the interface, your
production code should be able to use the default arguments. There's
no need to make the derived mock class specify the default arguments
again.

class Base {
public:
...
// Specify the default arguments in the interface.


virtual SceneNodeAdapter* createChildSceneNode(
const Ogre::Vector3& translate = Ogre::Vector3::ZERO,
const Ogre::Quaternion& rotate = Ogre::Quaternion::IDENTITY) = 0;

};

class Mock : public Base {
public:
// Not in the implementation.
MOCK_METHOD2(createChildSceneNode, SceneNodeAdapter*(


const Ogre::Vector3& translate,
const Ogre::Quaternion& rotate));

};

// In your production code:
Base* base = ...;
base->createChildSceneNode();

// In your tests:
Mock m;
EXPECT_CALL(m, createChildSceneNode(_, _))...;

Would this work for you?

2009/5/1 Zhanyong Wan (λx.x x) <w...@google.com>:

--
Zhanyong

Michael Williamson

unread,
May 2, 2009, 5:03:21 PM5/2/09
to Zhanyong Wan (λx.x x), Google C++ Mocking Framework
Hi Zhanyong

Yes I think this suggestion would work for me.
My question arose because I was thinking in terms of the C++ guideline (from Effective C++) that says you should keep default parameter values the same when overriding an inherited method. (Because the values used are determined at compile time, so if you change the defaults in a derived class you now get different values depending on the compile-time type you call the method with).
But I see your suggestion doesn't violate this. For starters nothing will actually be calling functions on the mock type (compile time). Even if anything did, it must specify the values so there can be no "different defaults".

My goal is to keep the adapter's interface "equivalent" to the real library (Ogre) interface. By equivalent I mean that with a compile time switch I can replace all adapter classes with the real library classes and it will behave the same (mainly for deployment builds, to avoid every library call being a virtual redirection in a real time 3D graphics app).

Thanks for your help.

- Wally

2009/5/2 Zhanyong Wan (λx.x x) <w...@google.com>
Reply all
Reply to author
Forward
0 new messages