我正在使用googletest学习单元测试,不确定如何覆盖某个功能。简而言之,我需要覆盖在母函数M内定义的lambda函数(比方说L)。M调用一个函数C(在另一个文件中定义),该函数将lambda函数L(回调)作为参数。我正在为M编写单元测试,需要调用M,模拟外部函数M,同时还要确保模拟C和正确覆盖L。
简而言之,对象-> 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使用存根,这将强制使用L(我有这个目前已实现的版本,以便能够与其余代码进行编译),是否仍然可以严格使用googletest样式获得此报道?
谢谢!
最终找到解决方案并将其发布以供参考;
我的解决方案是找到一种方法来在容器中存储我感兴趣的回调方法,为此创建辅助方法并从该向量中获取一些输出。
类型为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();
}
尽管不是最直接的解决方案,但事实证明它是有效的,我尝试列出一些在创建测试时可能遇到的用例。
祝您编码愉快!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句