gpt4 book ai didi

c++ - 如何模拟采用已定义的 lambda 函数并覆盖 lambda 函数的函数

转载 作者:太空宇宙 更新时间:2023-11-04 12:38:23 26 4
gpt4 key购买 nike

我正在使用 googletest 学习单元测试,但不确定如何覆盖函数。简而言之,我需要了解在母函数 M 中定义的 lambda 函数(假设为 L)。M 调用函数 C(在另一个文件中定义),该函数将 lambda 函数 L(回调)作为参数。我正在为 M 编写单元测试,需要调用 M,模拟外部函数 M,同时确保模拟 C 并正确覆盖 L。

简而言之,object->M 有 L,M 调用 C(L)。

谷歌测试有办法做到这一点吗?

我已经尝试过的一般形状:

    /* source code */
/* header */
struct Object
{/*struct methods*/
//M declaration
int M();
};

/* cpp file */
int M()
{
/* some operations */
auto L = [](int number){/* operations, returns 0; */};

int store; //storing the result of C
store = C(L);
}

/* other file */
int C(int* L(int))
{
/* some operations */
L(1);

return some_int;
}

单元测试文件代码:

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

using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::DoAll;
using ::testing::SetArgReferee;
using ::testing::SetArgPointee;
using ::testing::SetArrayArgument;
using ::testing::_;

/* mock class*/
class MockedFunctions
{
public:
/* going to put 5 ints for the sake of the example */
MOCK_METHOD1(C, int(int));
};

class TestObject : public ::testing::Test
{
public:
TestObject(){}
~TestObject(){}
protected:
Object *objectInstance;
virtual void SetUp()
{ objectInstance = new Object;}
virtual void TearDown()
{ delete objectInstance;}
};

/* test for function */
TEST_F(TestObject, test_M)
{
MockedFunctions test_C;

EXPECT_CALL(test_C, C(_))
.Times(1)
/* don't care about passed number to L */
.WillOnce(DoALL (SetArgPointee<0>(L(3)), Return(0));
/* coud put EXPECT_EQ as well */
objectInstance->M();
}

这在 .WillOnce 处给我一个错误,指出 L 未在此范围内声明。

注意,我不关心L的内容,只要覆盖就可以了。到目前为止,我发现关于这个主题的建议是模拟我的 lambda 函数 L,我不想在这里做,因为我需要覆盖它的代码作为函数 M 的一部分。

虽然我不需要,但在这种情况下,严格使用 GTest 风格(因为我的导师不知道如何继续这个 L 函数覆盖)并且可以使用 C 的 stub 来强制使用 L(我现在已经实现了这个版本,以便能够与其余代码一起编译),是否仍然可以严格使用 googletest 样式来获得此覆盖率?

谢谢!

最佳答案

最终找到解决方案并发布以供引用;

我的解决方案是找到一种方法将我感兴趣的回调方法存储在容器内,为此创建辅助方法并从该 vector 中获取一些输出。

  1. 在包含 MOCK_METHODX() 声明的类中,我首先使用 typedef 来更轻松地识别我的函数。
  2. 然后,在私有(private) block 中声明将用于传递函数的 vector 和 void 指针。
  3. 获取 vector 位置 x 处的内容的辅助方法(我曾遇到过在测试中多次运行模拟函数的情况,因此想查看每次调用的执行情况),添加到 vector ,清除内容(重置为其他测试)等等。
  4. MockedFunctions 类型的静态指针用于提供一个对象,以便在我们所需的数据被提取后“恢复”正常的模拟控制行为。

    //inside my header file.
    #include <gmock/gmock.h>
    #include <vector>

    class MockedFunctions {
    public:
    //lets say function L has params (int, void*)
    typedef int (myCb) (int arg_from_cb_L, void* objptr_from_cb_L));
    MockedFunctions(){}
    virtual ~MockedFunctions(){}

    //giving C more arguments than just the callback L
    MOCK_METHOD2(C, int(int arg1, int(*L)(int, void*));
    private:
    //note due to namespace limitations, I'm including the std prefix
    std::vector<myCb> callback_storage;
    void *cb_obj_copy;
    public:
    /* Multiple public blocks just for readability purposes.
    * Note the internal usage of vector methods.
    */
    void cb_clear(){
    if(callback_storage.empty())
    {
    callback_storage.clear();
    }
    }
    void cb_add(myCb callback){
    callback_storage.push_back(callback);
    }
    myCb* cb_result_at(int i){
    return callback_storage.at(i);
    }
    //to store one of the params from the passed callback
    void cb_copy_obj(void* obj){
    cb_obj_cb = obj;
    }
    void cb_get_obj_copy(){
    return cb_obj_copy;
    }
    };

    class TestMethods : public ::testing::Test
    {
    public:
    static std::unique_ptr<MockedMethods> testMockedMethods;
    TestMethods(){
    /* as we call other methods from MockedMethods apart from C,
    * it would trigger warnings. Using NiceMock hides them for
    * cleaner output.
    */
    testMockedMethods.reset(new ::testing::NiceMock<MockedMethods>());
    }
    ~TestMethods() override{
    testMockedMethods.reset();
    }
    virtual void SetUp() override {}
    virtual void TearDown() override {}
    };

现在,在我的 cpp 文件中,我定义了 C 并实例化了指针。

              std::unique_ptr<MockedMethods> TestObject::testMockedMethods(new MockedMethods() );
int C ( int arg1, int(*L)(int arg1_cb, void* arg2_cb)){
TestMethods::testMockedMethods->cb_add(L);
TestMethods::testMockedMethods->cb_copy_obj(arg2_cb);
/* to avoid complications, took L's return type of int and put a 0
* directly, we don't care at this point since we will overload the
* method afterwards.
*/
return TestMethods::testMockedMethods->C(arg1, 0);
}

至于实际测试,放在你认为合适的地方:

       class TestCaseClass : public TestMethods
{
public:
TestCaseClass(){}
~TestCaseClass(){}
protected:
//Here, object is the struct name mentioned previously in the question.
Object *instance;
// ...

virtual void SetUp()
{
instance = new Object();
// ...
}
virtual void TearDown()
{
delete instance;
}
};

TEST_F(TestCaseClass, test_M)
{
// testing method M from struct Object

/* Run tests normally on C, results will be stored. By our definition, a different object
* will be the one calling C, so pay attention to it.
*/
EXPECT_CALL(*testMockedMethods, C(_, _))
.Times(1)
.WillOnce(Return(1))
// I noticed at this point M above did not return anything, suppose it returns store
EXPECT_EQ(instance->M(), 1);

// Now to get coverage or data from our callback. First, get the method in cb_obj
MockedMethods::myObj* cb_method = testMockedMethods->cb_result_at(0);
// Now get one of its arguments, like that void*. Note we're using our get-ers
void* mock_object = testMockedMethods->cb_get_obj_copy();
/* And finally, call our method, finally getting coverage. You can pass
* various parameters for branching.
*/
cb_method(0, mock_object);

// Don't forget we clear the vector of contents in case we re-use it in another test.
testMockedMethods->cb_clear();
}

虽然不是最直接的解决方案,但它被证明是有效的,我尝试包含一些在创建测试时可能遇到的用例。

编码愉快!

关于c++ - 如何模拟采用已定义的 lambda 函数并覆盖 lambda 函数的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55395837/

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