Mocking using boost::shared_ptr and AMOP
I'm trying to write mocks using amop. I'm using Visual Studio 2008.
I have this interface class:
struct Interface {
virtual void Activate() = 0;
};
and this other class which receives pointers to this Interface
, like this:
struct UserOfInterface {
void execute(Interface* iface) {
iface->Activate();
}
};
So I try to write some testing code like this:
amop::TMockObject<Interface> mock;
mock.Method(&Interface::Activate).Count(1);
UserOfInterface user;
user.execute((Interface*)mock);
mock.Verifiy();
It works! So far so good, but what I really want is a boost::shared_ptr in the execute() method, so I write this:
struct UserOfInterface {
void execute(boost::shared_ptr<Interface> iface) {
iface->Activate();
}
};
How should the test code be now? I tried some things, like:
amop::TMockObject<Interface> mock;
mock.Method(&Interface::Activate).Count(1);
UserOfInterface user;
boost::shared_ptr<Interface> mockAsPtr((Interface*)mock);
user.execute(mockAsPtr);
mock.Verifiy();
It compiles, but obviously crashes, since at the end of the scope the variable 'mock' ge开发者_StackOverflow中文版ts double destroyed (because of the stack variable 'mock' and the shared_ptr).
I also tried to create the 'mock' variable on the heap:
amop::TMockObject<Interface>* mock(new amop::TMockObject<Interface>);
mock->Method(&Interface::Activate).Count(1);
UserOfInterface user;
boost::shared_ptr<Interface> mockAsPtr((Interface*)*mock);
user.execute(mockAsPtr);
mock->Verifiy();
But it doesn't work, somehow it enters an infinite loop, before I had a problem with boost not finding the destructor for the mocked object when the shared_ptr tried to delete the object.
Has anyone used amop with boost::shared_ptr successfully?
You may want to try using a more explicit cast. I'm not sure if this will work, but give it a try.
// Get the mock generator
boost::shared_ptr< amop::TMockObject<Interface> > mock
= boost::make_shared< amop::TMockObject<Interface> >;
// Get the mocked interface
boost::shared_ptr<Interface> imock = boost::dynamic_pointer_cast<Interface>(mock);
// Setup mock usage expectations
mock->Method(&Interface::Activate).Count(1);
// Run the test
UserOfInterface user;
user.execute(imock);
// Verify the expectations were met
mock->Verifiy();
Well, I never used amop, but perhaps this boost pattern will help..
To create a boost shared_ptr you can also use
boost::shared_ptr<Interface> mock(new amop::TMockObject<Interface>());
This way the mock object is not created on the stack and only destroyed if the reference counter in the shared_ptr gets to zero. Because this is essentially the same as your second try, another tip:
If you encounter problems that look like c++ is not finding the right destructor, you might introduces a virtual destructor in the base (interface) class. Does amop allow this?
class Interface{
virtual ~Interface() { }
...
};
You can give the shared_ptr a custom functor that will be called instead of delete when the reference count goes to zero.
The code then will look like this (I didn't try to compile it):
struct NoOpDel
{
void operator() (void *) { }
}
amop::TMockObject<Interface> mock;
mock.Method(&Interface::Activate).Count(1);
UserOfInterface user;
boost::shared_ptr<Interface> imock((Interface*)mock, NoOpDel())
user.execute(imock);
mock.Verify();
See Boost API doc for more details, you are interested in this constructor:
template<class Y, class D> shared_ptr(Y * p, D d);
Disclaimer: I'm the author of HippoMocks
Using HippoMocks you can specify that you expect the destructor is called at the end of your test. It also implicitly validates your expectations at the end of your test. That way it can even guard against a stray shared_ptr on the heap that you forgot to delete or a class that doesn't take ownership or forgets to delete the pointer in the case that you don't use a shared_ptr.
There is a way to use shared_ptr with amop
struct Interface {
virtual ~Interface() {}
virtual void Activate() = 0;
};
TEST(MockObjectMethodDestructor)
{
TMockObject<Interface> mock;
mock.Method(Destructor());
boost::shared_ptr<Interface> ptr((IInterface*)mock);
ptr.reset();
}
精彩评论