views:

71

answers:

3

Hello everyone :)

This is a revised/better written version of the question I asked earlier today -- that question is deleted now.

I have a project where I'm getting started with Google Mock. I have created a class, and that class calls functions whithin the Windows API. I've also created a wrapper class with virtual functions wrapping the Windows API, as described in the Google Mock CheatSheet. I'm confused however at how I should pass the wrapper into my class that uses that object. Obviously that object needs to be polymorphic, so I can't pass it by value, forcing me to pass a pointer. That in and of itself is not a problem, but I'm confused as to who should own the pointer to the class wrapping the API.

So... how should I pass the wrapper class into the real class to facilitate mocking?

Here's an example of what I mean:

struct A {
    virtual void SomeMethod(int x, int y)
    {
        ::SomeMethod(x, y);
    };
};

class Client
{
    A * method_;
public:
    Client(A * method = new A) : method_(method) {};
    void DoSomething()
    {
        method_->SomeMethod(42, 34);
    }
};

struct Mock : public A
{
    MOCK_METHOD2(SomeMethod, void(int, int));
};

TEST(MyTest, MyTestWithMock)
{
    Mock * mock = new Mock();
    EXPECT_CALL(*mock, SomeMethod(42, 34)).Times(1);
    Client client(mock); //Should *client* be responsable for deleting mock?
    client.DoSomething();
};

EXAMPLE 2:

struct A {
    virtual void SomeMethod(int x, int y)
    {
        ::SomeMethod(x, y);
    };
};

class Client
{
    A * method_;
public:
    Client(A * method) : method_(method) {};
    static Client Create()
    {
        static A;
        return Client(&A);
    }
    void DoSomething()
    {
        method_->SomeMethod(42, 34);
    }
};

struct Mock : public A
{
    MOCK_METHOD2(SomeMethod, void(int, int));
};

TEST(MyTest, MyTestWithMock)
{
    Mock  mock;
    EXPECT_CALL(mock, SomeMethod(42, 34)).Times(1);
    Client client(&mock);
    client.DoSomething();
};
+2  A: 

There's always the option of using shared_ptr; that would certainly solve the ownership problem.

James McNellis
A: 

Many ownership schemes are possible, but some are more maintainable than others. Whenever one object x contains another y by reference, I ask:

Who creates y? That party should also destroy y.

The advantage of this approach is that it works just as well when one or both objects are statically allocated, while approaches in which ownership is transferred must either use shared_ptr<> or make an assumption about whether y was dynamically allocated or not. The former introduces overhead, while the latter is fragile.

If more than one party could create the object, as your code currently does (it could be created either by the caller or by the constructor as a default argument), by far the simplest way is to use shared_ptr<>. But it's a good idea to avoid the situation where different parties could create a resource if you possibly can -- that is "shooting a mouse with an elephant gun".

j_random_hacker
So you're saying users of `Client` above should have to worry about a mocking class I'm using only for testing?
Billy ONeal
Not familiar with Google Mocks, but I assume you define an interface that's implemented by both real and mock objects and then pass pointers/references to the interface. I suggest having the caller always supply the `A*` to `Client`'s constructor to simplify ownership. Yes, this will complicate life for anything that creates a `Client` object (though users of already-created `Client`s are unaffected), but you can get around this by making `Client`'s ctor private and always asking a factory to create them for you. The factory "knows" whether or not to use a mock (e.g. based on a config file).
j_random_hacker
@j_random_hacker: Like the second example I just posted?
Billy ONeal
@Billy: It's a step in the right direction, but you should additionally (a) make `Client`'s ctor private to guarantee that no-one else can create a `Client` any other way, and (b) actually call your new static method `Create()` from the test method. Hmm I see now that using factories means you can't have a local `Client` object, rather you need to pass them back by pointer. And it's easiest for the factory to use `new` for allocating them, since they can then be passed back with an `auto_ptr<>` or `scoped_ptr<>`, which make cleanup automatic but have less overhead than `shared_ptr<>`.
j_random_hacker
@j_random_hacker: If client's constructor is private then how can the mock be inserted for the test? Why do I need to pass by pointer? The object in question isn't expensive to return by value which is what the Create method currently does. Most compilers are going to elide that copy in any case.
Billy ONeal
Upon more thinking, w.r.t. the lifetime of a contained object, using a factory function is exactly the same as using a public ctor with a default ctor as you're already doing, with the (small) disadvantage that it prevents you from allocating a static `Client` object. Either way, it's best for `Client` to store an `auto_ptr<A>` or `scoped_ptr<A>` and take that as ctor parameter, since that automatically cleans this up without overhead -- but it does prevent passing the address of a statically allocated object. OTOH `shared_ptr<A>` has a custom deleter which can be set to a no-op.
j_random_hacker
Although I no longer think a factory function buys you anything here, in answer to your most recent question, making the ctor private doesn't affect the ability to inject a mock because anyone who wants to make a `Client` must call your factory function `Create()`, which *does* have access to the private ctor. (Also you would you would normally make the factory function a separate `friend` function, or a method in a `friend` class, since there is actually no need for `Client` to know about it (separation of concerns).)
j_random_hacker
@j_random_hacker: Yes, but how the hell does Create know to insert a mock instead of the real thing?
Billy ONeal
Because `Create()` should be where the decision to mock or not is made. That could be done with `#ifdef`s (a compile-time solution) or by testing environment variables/command-line args/a config file (a runtime solution). You could even allow for choosing different types within a single run by putting `Create()` inside a stateful class with a `setMockPolicy()` method that can be called before `Create()`. The point being to get a `Create()` method that does not require parameters for every mockable object, so that "normal" (non-test) client code stays clean -- just like with your default args.
j_random_hacker
A: 

Virtual functions are not the only way to do this. You can also use templates which effectively gives you compile time polymorphism.

struct A {
    virtual void SomeMethod(int x, int y)
    {
        ::SomeMethod(x, y);
    };
};

template <class T>
class Client
{
    T method_;
public:
    Client() : method_(method) {};
    static Client Create()
    {
        return Client();
    }
    void DoSomething()
    {
        method.SomeMethod(42, 34);
    }

    T &GetMethod()
    {
        return method_;
    }
};

struct Mock
{
    MOCK_METHOD2(SomeMethod, void(int, int));
};

TEST(MyTest, MyTestWithMock)
{
    Client<Mock> client;
    EXPECT_CALL(client.GetMethod(), SomeMethod(42, 34)).Times(1);
    client.DoSomething();
};
R Samuel Klatchko
Yes -- but this forces me to put my entire implementation in header files. Nothing wrong with that, but there are some classes I'd rather not do that to because they are relatively large.
Billy ONeal