How should I pass an object wrapping an API to a class using that API?
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 function开发者_运维问答s 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();
};
There's always the option of using shared_ptr
; that would certainly solve the ownership problem.
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".
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();
};
精彩评论