gpt4 book ai didi

c++ - 通过setargreferee传递 vector 时,gtest中的EXPECT_CALL未实现

转载 作者:行者123 更新时间:2023-12-02 10:10:00 31 4
gpt4 key购买 nike

#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();
}
我想测试MyClassA::updateStatus方法。在这种情况下,我想在myTestInfoList EXPECT_CALL内的MyInfo对象上设置返回值InfoState::ON。
然后,我将列表放到SetArgReferee进行测试的方法中。在执行info.getState()时,它返回InfoState::OFF,并且gtest说“无趣的模拟函数调用-返回默认值。”。
为什么会出现此问题,我该如何测试?

最佳答案

正如Quarra注释一样,主要问题是复制构造函数。我不是Google Test专家,但是我找到了解决您问题的方法。
根据GMock,我发现无法复制模拟对象-这是Google Test实现者的设计原则和决定。 Here this decision has been justified早在2009年。
因此,通过不在模拟对象内部定义copy构造函数,它将被删除(live 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;
然而,这里的主要问题实际上是复制构造函数的实际需求,这是由两个因素引起的:
  • 就像我在GMock之前说过的那样,它删除了复制构造,即使您将创建自己的实现,也不会复制所有EXPECT_CALL和其他GMock基本功能!这正是您遇到的问题。因此,您已经创建了一个自定义副本构造函数,所有GMock功能都消失了。尽管此构造函数为空,但无论如何都无法使用。
  • MyInfo(const MyInfo&){};
  • 第二个问题是std::vector,您正在使用自己的需求(在此用例中),该类型符合CopyConstructible概念。因此,这将不起作用。

  • 让我担心的是, EXPECT_CALL使用副本而不是移动语义或传递引用。尽管您已明确设置该参数应为引用(而不是副本!) SetArgReferee<0>(myTestInfoList),但仍可以执行此操作。此外,根据设计, GMock对象不可复制。对我来说,这看起来像是设计缺陷或错误,但我不是 Google Test专家。我将对此进行更多研究,并可能向 GTest实现者提出错误报告/问题。
    好的,但是要找到解决方案,我们需要首先在 GMock API中找到一个不使用副本的方法,然后使用不调用副本构造函数的 std::vector功能。
    第一个问题将通过将 EXPECT_CALL更改为 ON_CALL来解决,为了打开调用 std::vector功能的可能性,我们还将使用 Invoke API中的 GMock
    ( 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();
    }
    这适用于显式删除的 copy constructor-> MyInfo(const MyInfo&) = delete;,但逻辑现在也已删除。
    为了克服第二个问题,即 STL复制,我们可以简单地使用 std::swap并填充传递的 std::vector&。交换值不会复制数据-因此我们很高兴。
        ON_CALL(testObj.m_serviceClient, getInfo(::testing::_))
    .WillByDefault(::testing::Invoke(
    [&myTestInfoList](std::vector<MyInfo> &myInfoList)
    {
    std::swap(myInfoList, myTestInfoList);
    return true;
    }));
    这是工作的 solution
    如前所述,我将尝试调查为什么GMock EXPECT_CALL强制复制。

    关于c++ - 通过setargreferee传递 vector 时,gtest中的EXPECT_CALL未实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64062237/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com