c++ 如何使用Google Mock模拟模板化方法?

z0qdvdin  于 2023-04-01  发布在  Go
关注(0)|答案(3)|浏览(241)

我试图模仿一个模板化的方法。
下面是包含要模拟的方法的类:

class myClass
{
public:
    virtual ~myClass() {}

    template<typename T>
    void myMethod(T param);
}

如何使用Google Mock模拟myMethod方法?

lnxxn5zx

lnxxn5zx1#

在以前版本的Google Mock中,你只能模拟虚函数,请参阅项目页面中的文档。
最近的版本允许模拟非虚拟方法,使用他们所谓的 *hi-perf依赖注入 *。
正如用户@congusbongus在下面的评论中所说:
GoogleMock依赖于添加成员变量来支持方法模拟,由于您不能创建模板成员变量,因此无法模拟模板函数
Michael哈灵顿在googlegroups的评论链接中提出了一个解决方案,就是将模板方法专门化,这些方法将调用一个可以被模仿的普通函数。它不能解决一般情况,但可以用于测试。

struct Foo
{
    MOCK_METHOD1(GetValueString, void(std::string& value));

    template <typename ValueType>
    void GetValue(ValueType& value); 

    template <>
    void GetValue(std::string& value) {
        GetValueString(value);
    } 
};
mum43rcc

mum43rcc2#

以下是原始帖子,并附有评论以帮助理解:

struct Foo 
    { 
        // Our own mocked method that the templated call will end up calling.
        MOCK_METHOD3(GetNextValueStdString, void(const std::string& name, std::string& value, const unsigned int streamIndex)); 

        // If we see any calls with these two parameter list types throw and error as its unexpected in the unit under test.
        template< typename ValueType > 
        void GetNextValue( const std::string& name, ValueType& value, const unsigned int streamIndex ) 
        { 
            throw "Unexpected call."; 
        } 
        template< typename ValueType > 
        void GetNextValue( const std::string& name, ValueType& value ) 
        { 
            throw "Unexpected call."; 
        } 

        // These are the only two templated calls expected, notice the difference in the method parameter list. Anything outside
        // of these two flavors is considerd an error.
        template<> 
        void GetNextValue< std::string >( const std::string& name, std::string& value, const unsigned int streamIndex ) 
        { 
            GetNextValueStdString( name, value, streamIndex ); 
        } 
        template<> 
        void GetNextValue< std::string >( const std::string& name, std::string& value ) 
        { 
            GetNextValue< std::string >( name, value, 0 ); 
        } 
    };
dw1jzc5e

dw1jzc5e3#

这里的解决方案不需要手动实现每个模板示例化,如果有很多不同的模板示例化,这将特别有用。

struct Foo
{
  template <typename T>
  struct FooImpl
  {
    MOCK_METHOD(void, myMethod, (const T& value), ());
  };

  template <typename T>
  void myMethod(const T& value)
  {
    GetMock<T>()->myMethod(value);
  }

  template <typename T>
  std::shared_ptr<FooImpl<T>> GetMock()
  {
    std::shared_ptr<FooImpl<T>> result;
    std::shared_ptr<void> voidValue;
    if (!(voidValue = mCachedImpls[typeid(T).name()])
    {
      result = std::make_shared<FooImpl<T>>();
      mCachedImpls[typeid(T).name()] = std::reinterpret_pointer_cast<void>(result);
    }
    else
    {
      result = std::reinterpret_pointer_cast<FooImpl<T>>(voidValue);
    }

    return result;
  }

private:
  std::unordered_map<std::string, std::shared_ptr<void>> mCachedImpls;
};

Mock可以这样准备:

Foo foo;
EXPECT_CALL(*(foo.GetMock<int>()), myMethod(_)).Times(1);

相关问题