单元测试,模拟和unique_ptr

sti*_*ijn 5 c++ smart-pointers mocking unique-ptr c++11

有一个正在测试的类目前接受unique_ptr< Interface >&&它的构造函数,表示它想要接受一个接口实现的单一所有权.当想要使用Interface模拟测试此类时会出现问题:模拟框架(HippoMocks)仅向我提供了我Interface*不拥有的类,因此无法删除.

在测试const shared_ptr< Interface >&作为参数的类之前我遇到了同样的问题,但通过提供自定义的no-op删除器修复了这个问题:

template< class T >
void NoDelete( T* )
{
}

  //create a shared_ptr without effective deleter
template< class T >
std::shared_ptr< T > mock_shared( T* t )
{
  return std::shared_ptr< T >( t, NoDelete< T > );
}

Interface* iface = mocks.GetMeAMock< Interface >();
DoStuffWithSharedPtrOfInterface( mock_shared< Interface >( iface ) );
Run Code Online (Sandbox Code Playgroud)

对unique_ptr的类似修复并没有真正解决,因为删除器是一个模板参数:

template< class T >
struct NoDelete
{
  void operator ()( T* )
  {
  }
};

  //oops this is totally useless since std::unique_ptr< T, NoDelete< T > >
  //is not quite the same type as std::unique_ptr< T >
template< class T >
std::unique_ptr< T, NoDelete< T > > mock_unique( T* t )
{
  return std::unique_ptr< T, NoDelete< T > >( t, NoDelete< T >() );
}
Run Code Online (Sandbox Code Playgroud)

这有解决方法吗?或者我不应该首先在这里使用unique_ptr?

更新 我给了这个去; 应该工作,但sizeof(ptr)现在是8,很难说它有什么影响.

  //use CustomUniquePtr::type instead of uniqe_ptr
template< class T >
struct CustomUniquePtr
{
  typedef typename std::unique_ptr< T, void (*) ( T* ) > type;
}

  //use everywhere
template< class T >
CustomUniquePtr< T >::type make_unique( T* p )
{
  return CustomUniquePtr< T >::type( p, Delete< T > );
}

  //use when mocking, doe not delete p!
template< class T >
CustomUniquePtr< T >::type mock_unique( T* p )
{
  return CustomUniquePtr< T >::type( p, NoDelete< T > );
}
Run Code Online (Sandbox Code Playgroud)

eca*_*mur 7

shared_ptr将其删除器与其他簿记数据(refcount等)一起存储在堆上; unique_ptr没有堆开销,因此删除器必须存储在对象中并成为类型的一部分.

您可以模板化构造函数Deleter并将其转换unique_ptr为a shared_ptr来擦除删除器类型.

更好(取决于接口的大小)将提供Interface转发给模拟的代理对象Interface *.


小智 2

Hippomock 已经提供了解决这个问题的方法。如果您有一个带有虚拟析构函数的接口,那么您所需要做的就是注册析构函数的期望。模拟不会通过对其析构函数的调用而销毁,因为它是模拟析构函数,但必须设置对析构函数调用的期望。

MockRepository mocks;
// create the mock
std::unique_ptr<IFoo> foo( mocks.Mock<IFoo>() );

// register the expectation for the destructor
mocks.ExpectCallDestructor( foo.get() );

// call to mocks destructor ok, mock not destroyed
foo.reset( nullptr );
Run Code Online (Sandbox Code Playgroud)