简体   繁体   English

通过 setargreferee 传递向量时,gtest 中未实现 EXPECT_CALL

[英]Unfulfilled EXPECT_CALL in gtest when passing vector by setargreferee

#include <gtest/gtest.h>
#include <gmock/gmock.h>

enum class InfoState : uint8_t
{
    OFF     = 0,
    ON      = 1,

};

class MyInfo
{
public:
    MyInfo(){};
    MyInfo(const MyInfo&){};
    MyInfo& operator=(const MyInfo&){}
    MOCK_METHOD0(getState, InfoState(void));
};

class ServiceClient
{
public:
    MOCK_METHOD1(getInfo, bool(std::vector<MyInfo> &myInfoList));
};

class MyClassA
{
public:
    ServiceClient m_serviceClient;

    void updateStatus()
    {
        std::vector<MyInfo> myInfoList;
        if (m_serviceClient.getInfo(myInfoList))
        {
            for (auto& info: myInfoList)
            {
                if (InfoState::ON == info.getState())
                {
                    //notifyObservers(true);
                    break;
                }
            }
        }
    }
};

TEST(infoTest, test1)
{
    MyClassA testObj;

    std::vector<MyInfo> myTestInfoList(1);

    EXPECT_CALL(myTestInfoList[0], getState()).WillOnce(::testing::Return(InfoState::ON));

    EXPECT_CALL(testObj.m_serviceClient, getInfo(::testing::_))
         .WillOnce(::testing::DoAll(::testing::SetArgReferee<0(myTestInfoList),::testing::Return(true)));

    testObj.updateStatus();
}

I want to test MyClassA::updateStatus method.我想测试 MyClassA::updateStatus 方法。 In this case I want to set on MyInfo object inside myTestInfoList EXPECT_CALL with return value InfoState::ON.在这种情况下,我想在 myTestInfoList EXPECT_CALL 中的 MyInfo 对象上设置返回值 InfoState::ON。 Then I put my list to tested method by SetArgReferee.然后我将我的列表放入 SetArgReferee 的测试方法中。 When it comes to execution of info.getState() it returns InfoState::OFF and gtest says "Uninteresting mock function call - returning default value.".当涉及到 info.getState() 的执行时,它返回 InfoState::OFF 并且 gtest 说“无趣的模拟函数调用 - 返回默认值。”。 Why this problem occurs and how I can test it ?为什么会出现这个问题,我该如何测试?

As Quarra comment, the main problem is a copy constructor.作为夸拉评论,主要问题是复制构造函数。 I am not a Google Test specialist, yet I found a solution to your problem.我不是Google Test专家,但我找到了解决您问题的方法。

As per GMock , I found out that mocked objects cannot be copied - this is the design principle and the decision of Google Test implementers.根据GMock ,我发现不能复制GMock对象 - 这是Google Test实施者的设计原则和决定。 Here this decision has been justified back in 2009.早在 2009 年,这一决定就得到了证明

Therefore by not defining the copy constructor inside of mocked objects, it will be deleted ( live code ).因此,通过不在模拟对象内部定义复制构造函数,它将被删除(实时代码)。 Here is the error code这是错误代码

/opt/compiler-explorer/libs/googletest/release-1.10.0/googlemock/include/gmock/gmock-spec-builders.h:1483:3: note: 'FunctionMocker' has been explicitly marked deleted here

  FunctionMocker(const FunctionMocker&) = delete;

Yet the main problem here is in fact the actual need of a copy constructor, and this is caused by two factors:然而这里的主要问题实际上是复制构造函数的实际需要,这是由两个因素引起的:

  1. As I stated before GMock by design deletes copy construction, and even if you will create your own implementation - all EXPECT_CALL and other GMock essential functionalities would not be copied!正如我在 GMock by design 删除复制构造之前所说的那样,即使您将创建自己的实现 - 所有EXPECT_CALL和其他 GMock 基本功能都不会被复制! This is exactly the issue you are having.这正是您遇到的问题。 So you've created a custom copy constructor, and all GMock functionality is gone.所以你已经创建了一个自定义的复制构造函数,所有的 GMock 功能都消失了。 Despite the fact that this constructor is empty - it will not work out of the box anyway.尽管这个构造函数是空的 - 它无论如何都不会开箱即用。
MyInfo(const MyInfo&){};
  1. Second problem is the std::vector which you are using demands from you (in this use-case) that the type meets the CopyConstructible concept.第二个问题是您使用的std::vector要求(在此用例中)该类型符合CopyConstructible概念。 Therefore this will not work.因此这是行不通的。

What concerns me is the fact that EXPECT_CALL is using copy instead of move semantics or passing a reference.我担心的是EXPECT_CALL使用复制而不是移动语义或传递引用的事实。 This is done despite the fact that you explicitly set that argument shall be a reference (not a copy!) SetArgReferee<0>(myTestInfoList) .尽管您明确设置该参数应为引用(而不是副本!) SetArgReferee<0>(myTestInfoList) Moreover by design GMock objects are not copyable.此外,按照设计, GMock对象是不可复制的。 This looks like a design flaw or bug to me, yet I am not a Google Test expert.对我来说,这看起来像是设计缺陷或错误,但我不是Google Test专家。 I will do more research on that and maybe raise a bug report/question to GTest implementors.我将对此进行更多研究,并可能向GTest实现者提出错误报告/问题。

Ok but to find the solution we need to first find a method in GMock API which do not use a copy, and afterward use std::vector functionality which is not calling a copy constructor.好的,但要找到解决方案,我们需要首先在GMock API找到一个不使用副本的方法,然后使用不调用复制构造函数的std::vector功能。

The first problem will be solved by changing EXPECT_CALL to ON_CALL and to open the possibility for calling std::vector functionality we will also use Invoke from GMock API.第一个问题将通过将EXPECT_CALL更改为ON_CALL并打开调用std::vector功能的可能性来解决,我们还将使用来自GMock API 的Invoke ( Live code ) 实时代码

TEST(infoTest, test1)
{
    MyClassA testObj;

    std::vector<MyInfo> myTestInfoList(1);

    ON_CALL(myTestInfoList[0], getState()).WillByDefault(::testing::Invoke(
            []()
            {
                return InfoState::ON;
            }));

    ON_CALL(testObj.m_serviceClient, getInfo(::testing::_))
         .WillByDefault(::testing::Invoke(
            [](std::vector<MyInfo> &myInfoList)
            {
                return true;
            }));

    testObj.updateStatus();
}

This works with explicitly deleted copy constructor -> MyInfo(const MyInfo&) = delete;这适用于显式删除的copy constructor -> MyInfo(const MyInfo&) = delete; yet logic is also deleted right now.然而,逻辑现在也被删除了。

To overcome the second problem, which is STL copy, we can simply use std::swap and fill passed std::vector& .为了克服第二个问题,即STL复制,我们可以简单地使用std::swap并填充传递的std::vector& Swapping values doesn't copy the data - hence we are good to go.交换值不会复制数据 - 因此我们很高兴。

    ON_CALL(testObj.m_serviceClient, getInfo(::testing::_))
         .WillByDefault(::testing::Invoke(
            [&myTestInfoList](std::vector<MyInfo> &myInfoList)
            {
                std::swap(myInfoList, myTestInfoList);
                return true;
            }));

here is the working solution .这是工作解决方案

As said before I will try to investigate why GMock EXPECT_CALL forces a copy.如前所述,我将尝试调查为什么 GMock EXPECT_CALL强制复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 嵌套预期调用时,gtest EXPECT_CALL 不起作用 - gtest EXPECT_CALL does not working when expected call is nested 如何使用 gtest 模拟 EXPECT_CALL - How to simulate an EXPECT_CALL with gtest 使用gtest EXPECT_CALL时的竞争条件段错误,而另一个期望是使用相同的方法 - Race condition segfault when using gtest EXPECT_CALL while another expectation is exercising the same method object构造前如何调用EXPECT_CALL gtest宏 - How to call EXPECT_CALL gtest macro before the object construction 在 gtest 中模拟纯虚函数并使用 expect_call 进行测试 - Mocking a pure virtual function in gtest and testing with expect_call GTest测试用例“EXPECT_CALL”编译错误 - GTest test case “EXPECT_CALL” compilation error Gtest:如何在expect_call中每次根据增加的数字返回不同的字符串值? - Gtest: how to return different string value based on an increasing number every time in the expect_call? GTest和GoogleMock EXPECT_CALL在Windows中失败,使用char * param在Mac上传递 - GTest and GoogleMock EXPECT_CALL Fails in windows, passes on Mac with char * param Googletest (gtest) / googlemock (gmock):为什么“interleav[ing] `EXPECT_CALL()`s and calls to the mock functions”未定义行为? - Googletest (gtest) / googlemock (gmock): Why is “interleav[ing] `EXPECT_CALL()`s and calls to the mock functions” undefined behavior? 在 EXPECT_CALL 中使用变量 - use of variable in EXPECT_CALL
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM