通过其构造函数将依赖项传递给包装器对象

时间:2012-10-02 08:49:05

标签: c++

我有以下测试:

TestGet(): _interface(), _db(_interface)
{
    _interface.get = mockGet;
}

在测试此类时使用:

class DB: public IDB
{
public:
   explicit DB(Interface_T& interface):
     _interface(interface)
   {
   }

   ...

private:
   Interface_T _interface;
};

Interface_T是一个在结构中实现的C接口,并从C api传递给我。我希望使用DB类作为C接口的包装器。

但请注意,DB将接口对象复制到其成员_interface。因此行:

_interface.get = mockGet;
从数据库对象的角度来看,

没有任何影响,尽管这是我编写测试类时的意图。你会如何重写TestGet()来解决这个错误?您如何向DB类的客户端呈现它复制传递给它的值?

4 个答案:

答案 0 :(得分:1)

假设您的意图是TestGetInterface_T使用的DB对象上设置成员,您可以:

一个。推迟构建DB

TestGet(): _interface(), _db(NULL)
{
    _interface.get = mockGet;

    // Using a raw pointer here for minimalism, but in practice
    // you should prefer a smart pointer type.
    _db = new DB(_interface);
}

B中。如果您可以控制Interface_T类,则可以添加一个直接初始化Interface_T::get的构造函数。然后你可以这样做:

TestGet(): _interface(mockGet), _db(_interface)
{
}

℃。如果您可以控制DB类,则可以将其更改为共享所提供的Interface_T的所有权(例如通过boost::shared_ptr),添加B中的构造函数,或添加一个访问者其内部Interface_T成员。

答案 1 :(得分:1)

因此,在db get构造之前,您需要使接口正确。嗯,这很容易。只需在函数中创建适当的接口并将结果传递给构造函数:

Interface_T makeMockInterface()
{
    Interface_T interface;
    // I presume you will first use the C API to initialize it and than
    interface.get = mockGet;
}

TestGet() : _db(makeMockInterface())
{
}

Interface_T的值由makeMockInterface返回,但由于底层机器代码实际上通过将对象复制到调用者提供的空间来返回对象,因此大多数编译器实际上会忽略副本并构造对象直接调用者提供的空间(标准明确允许这样做。)

TestGet类不需要单独的_interface成员,因为_db包含它并且它们不会被共享,所以没有意义。

编辑: DB构造函数采用非const引用,即使它只是复制了对象,const引用也足够了。修复构造函数会更好,但是如果它不是一个选项,我会把它转换为非const。这需要两个强制转换:

TestGet() : _db(const_cast<Interface_T &>(static_cast<const Interface_T &>(makeMockInterface())))

或一个简单的模板助手:

template <typename T>
T &lvalue_cast(const T &v) { return const_cast<T &>(v); }

TestGet() : _db(lvalue_cast(makeMockInterface()))

由于临时实际上是可变的,只是不绑定到非const引用作为安全措施,两者都有明确定义。

答案 2 :(得分:0)

这是基于Jan Hudec的评论:

class TestGet : public ::testing::Test 
{
protected:
   TestGet() 
      :  _db(interfaceFactory())
   {
   }

   Interface_T interfaceFactory()
   {
      Interface_T interface;
      _interface.get = mockGet;
      return interface;
   }

   DB _db;
};

我喜欢这种干净的方法。

答案 3 :(得分:0)

有几种方式,包括某种inversion of control

我最喜欢的是:

  • 使用对接口的引用
  • 将对象传递给构造函数
  • 使用工厂模式创建对象,并返回某种共享指针(再次使用接口)

这样的事情(假设你有基础抽象类):

struct Interface
{
  virtual ~Interface(){}
  virtual void foo() = 0;
};
struct Derived : public Interface
{
  void foo(){}
};

struct A
{
  A ( std::shared_ptr< Interface > obj_ ) : obj( obj_ )
  {}

  std::shared_ptr< Interface > obj;
};

//...
A myA( std::shared_ptr< Interface >( new Derived ) );
// ..

上面的例子是传递给构造函数。