2017-02-28 46 views
3

如果一個接口有一個函數來創建一個刪除copy-ctor的對象,如何模擬這個函數? Gmock似乎在內部使用對象的拷貝構造函數。如何模擬方法返回刪除copy-ctor對象?

E.g.

// The object with deleted copy-ctor and copy-assignment 
class TTest 
{ 
public: 
    TTest() = delete; 
    TTest(const TTest&) = delete; 
    TTest& operator=(const TTest&) = delete; 
    TTest(TTest&&) = default; 
    TTest& operator=(TTest&&) = default; 

    explicit TTest(int) { 
    } 
}; 

// My interface to mock 
class MyInterface 
{ 
    public: 
     virtual ~MyInterface() {} 
     virtual TTest GetUniqueTest() = 0; 
}; 

// The mock 
class MockMyInterface: public MyInterface{ 
    public: 
     MOCK_METHOD0(GetUniqueTest, TTest()); 
} 

編譯錯誤說:

gmock/gmock-spec-builders.h:1330:20: error: use of deleted function 'TTest::TTest(const TTest&)' 
    T retval(value_); 
... 
gmock/gmock-actions.h:190:52: error: use of deleted function 'TTest::TTest(const TTest&)' 
     internal::BuiltInDefaultValue<T>::Get() : *value_; 
... 
gmock/internal/gmock-internal-utils.h:371:71: error: use of deleted function 'TTest::TTest(const TTest&)' 
     *static_cast<volatile typename remove_reference<T>::type*>(NULL)); 

如果該方法返回std::unique_ptr<T>,誤差是相同的,因爲std::unique_ptr<T>已刪除拷貝構造函數也是如此。

所以我的問題是:如何模擬這樣的方法,返回刪除copy-ctors的對象?

我使用googletest v1.7,GCC 5.3.0和Ubuntu 14.04.1。

回答

3

正如在Mine的評論中所提到的,Google Test 1.8似乎支持嘲笑這些功能(documentation)。

至於1.7我找到了解決方案here

首先,創建一個實用工具類來包裝不可複製的對象:

template <typename T> 
class Mover 
{ 
public: 
    Mover(T&& object) 
     : object(std::move(object)), 
     valid(true) 
    { 
    } 

    Mover(const Mover<T>& other) 
     : object(const_cast<T&&>(other.object)), 
     valid(true) 
    { 
     assert(other.valid); 
     other.valid = false; 
    } 

    Mover& operator=(const Mover& other) 
    { 
     assert(other.valid); 
     object = const_cast<T&&>(other.object); 
     other.valid = false; 
     valid = true; 
    } 

    T& get() 
    { 
     assert(valid); 
     return object; 
    } 

    const T& get() const 
    { 
     assert(valid); 
     return *object; 
    } 

private: 
    T object; 
    mutable bool valid; 
}; 

template <typename T> 
inline Mover<T> Movable(T&& object) 
{ 
    return Mover<T>(std::move(object)); 
} 

,然後創建一個代理模擬:

class MockMyInterface : public MyInterface 
{ 
public: 
    MOCK_METHOD0(GetUniqueTest_, Mover<TTest>()); 
    TTest GetUniqueTest() 
    { 
     return std::move(GetUniqueTest_().get()); 
    } 
} 
+0

偉大的答案,它工作得很好! – Mine

+0

谷歌測試** 1在我看來。8 **似乎支持嘲笑這些功能:https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#mocking-methods-that-use-move-only-types它可能更新爲googletest v1.8是個好主意。 – Mine

+0

@我是的,我也發現這個,但沒有時間來驗證:)也許當你確認你也可以自我回答;) – BartoszKP

1

回答我的問題在這裏只是提供更新的信息。

使用googletest 版本1.8.0或更高版本,它引入了ByMove(...)並且本機支持僅返回移動類型。

因此,代碼編譯OK:

class MockMyInterface: public MyInterface{ 
    public: 
     MOCK_METHOD0(GetUniqueTest, TTest()); 
} 

但在運行時會拋出異常,因爲gmock不知道如何恢復默認TTest

C++ exception with description "Uninteresting mock function call - returning default value. 
    Function call: GetUniqueTest() 
    The mock function has no default action set, and its return type has no default value set." thrown in the test body. 

這可以通過設置來輕鬆地解決模擬類默認動作:

ON_CALL(*this, GetUniqueTest()).WillByDefault(Return(ByMove(TTest(0)))); 

注意:對於std::unique_ptr<T>它沒有問題,因爲它具有默認構造函數,默認情況下會返回nullptrunique_ptr

因此以上把所有在一起,如果用googletest 1.8.0,我們可以這樣做:

// My interface to mock 
class MyInterface 
{ 
    public: 
     virtual ~MyInterface() {} 
     virtual TTest GetUniqueTest() = 0; 
     virtual std::unique_ptr<int> GetUniqueInt() = 0; 
}; 

// The mock 
class MockMyInterface: public MyInterface{ 
    public: 
     MOCK_METHOD0(GetUniqueTest, TTest()); 
     MOCK_METHOD0(GetUniqueInt, std::unique_ptr<int>()); 
     MockMyInterface() { 
      ON_CALL(*this, GetUniqueTest()) 
       .WillByDefault(Return(ByMove(TTest(0)))); 
     } 
}; 

參考:Mocking Methods That Use Move-Only Types

相關問題