我需要模拟一个具有指针指针参数的函数(因此是一个**参数)。
我尝试了下面的一段伪代码(注意:NON_ZERO_ENUM_MEMBER代表一个值不等于0的枚举值)
my_arg_type argument;
argument.enummember = NON_ZERO_ENUM_MEMBER;
EXPECT_CALL( *my_mock, mock_function( _, _ ) )
.times(1)
.WillOnce( DoAll( SetArgPointee<1>( &argument ), Return( 0 ) ) );
这构建正常,但是当我运行我的测试参数时.enummember是0。
如果我是正确的,这是由googlemock制作我想要返回的内容的副本,并且在SetArgPointee的情况下为它创建一个指针(因此,如果是正常的*可以说SetArgPointee(参数) )。 但在这种情况下,我给出一个地址,然后该地址变为指针。但是不存储变量的实际值(如果我的假设是正确的)。
googlemock是否有一种标准的方式可以处理**参数,或者我是否需要创建一个更全面的“全球”版本。变量并返回该变量的地址?
/ 编辑 /将我之前的编辑内容移至第二个回复以保持原始问题的简短
答案 0 :(得分:1)
在没有看到更多代码的情况下,我无法弄清楚你的argument.enummember如何变为0。 话虽如此,应该可以使用google mock将指针设置为指针参数。
从一个简单的类开始(类似于原始帖子中提到的)。
class argument {
public:
int enummember;
};
然后设置一个模拟类,它有一个名为&#34;运行&#34;的模拟方法。其参数是指向指针的指针。
class Helper {
public:
MOCK_METHOD1(run, int(argument ** a));
};
设置一些初始条件
argument * a = new argument;
a->enummember = 111;
argument * b = new argument;;
b->enummember = 222;
设定期望:
// When we call this function, it will set the given argument to b.
Helper helper;
EXPECT_CALL(helper, run(_))
.Times(1)
.WillOnce(DoAll(SetArgPointee<0>(b), Return(99)));
执行命令
int rc = helper.run(&a);
你应该看到,rc = 99并且a等于b(它们指向相同的地址)。
这可以通过打印出这样的东西(运行命令之前和之后)来验证。
std::cout << "a enummember:" << a->enummember << std::endl;
std::cout << "a (address of the pointer):" << a << std::endl;
std::cout << "b enummember:" << b->enummember << std::endl;
std::cout << "b (address of the pointer):" << b << std::endl;
答案 1 :(得分:0)
/ 编辑 /从原始问题移到此处,以保持原始问题简短
根据要求提供更多信息(我不允许提供确切的代码,因此我必须坚持使用伪实现)。我想首先避免这种情况,因为(正如你所看到的)它让我的问题很长;-))
@Dan:我看到你的回答基本上归结为我的“更全球化”的问题。解决方案,但比更好的论证;-)。此时我不会将其设置为“正确答案”,因为我想看看是否有更好的信息,但是只要没有人认为这是正确的答案。
一些背景信息:
注意:由于实际上有2个模块(甚至更多,但对于这个特定问题并不感兴趣)被模拟涉及我已经用上面的例子替换名称 mock_function em> MTBM_mock_function 使示例更加清晰。
my_arg_type在MTBM.h中定义:
typedef enum
{
ZERO_ENUM_MEMBER = 0,
NON_ZERO_ENUM_MEMBER
} MTBM_ENUM_TYPE;
typedef struct
{
MTBM_ENUM_TYPE enummember;
... //some other members not interesting for our test
} my_arg_type;
我的SUT代码归结为:
#include MTBM.h
#include OMM.h
int SUT_function_to_be_tested( void )
{
int error = 0;
my_arg_type *argument_ptr = NULL;
int interesting_value_OMM = 0;
error = SUT_code_which_setups_memory_for_argument_and_initializes_it_to_ZERO_ENUM_MEMBER( argument_ptr );
if (error == 0)
{
error = MTBM_mock_function( TRUE, &argument_ptr )
}
if ((error == 0) && (argument_ptr->enummember == ZERO_ENUM_MEMBER )
{
error = OMM_function_not_interesting_for_this_particular_test();
}
if ((error == 0) && (argument_ptr->enummember == NON_ZERO_ENUM_MEMBER )
{
error = OMM_function_interesting_for_this_particular_test( &interesting_value_OMM );
}
...
return(error);
}
我创建的模拟是:
extern "C"
{
#include MTBM.h
#include OMM.h
}
struct helper
{
virtual ~helper() {}
virtual int MTBM_mock_function( bool lock, my_arg_type **argument ) = 0;
virtual int OMM_function_not_interesting_for_this_particular_test( void ) = 0;
virtual int OMM_function_interesting_for_this_particular_test( int *interesting_value_OMM) = 0;
};
struct Mock: public helper
{
MOCK_METHOD2( MTBM_mock_function, int( bool lock, my_arg_type **argument ) );
MOCK_METHOD0( OMM_function_not_interesting_for_this_particular_test, int( void ) );
MOCK_METHOD1( OMM_function_interesting_for_this_particular_test, int( int *interesting_value_OMM) );
}
Mock *my_mock
extern "C"
{
int MTBM_mock_function( bool lock, my_arg_type **argument )
{
my_mock->MTBM_mock_function( lock, argument );
}
int OMM_function_not_interesting_for_this_particular_test( void )
{
my_mock->OMM_function_not_interesting_for_this_particular_test();
}
int OMM_function_interesting_for_this_particular_test( int *interesting_value_OMM )
{
my_mock->OMM_function_interesting_for_this_particular_test( interesting_value_OMM );
}
}
my_mock在灯具中初始化(请参阅this previous question了解另一个我指定灯具结构的unittest)
我的第一次尝试(以上问题的基础)是:
void setup_mocks( void )
//There are actually a lot more mocks, but not interesting for this particular question
//except that I used a function to setup the mocks to keep the actual TEST_F code clear
{
my_arg_type argument;
argument.enummember = NON_ZERO_ENUM_MEMBER;
EXPECT_CALL( *my_mock, MTBM_mock_function( _, _ ) )
.times(1)
.WillOnce( DoAll( SetArgPointee<1>( &argument ), Return( 0 ) ) );
EXPECT_CALL( *my_mock, OMM_function_interesting_for_this_particular_test( _ ) )
.times(1)
.WillOnce( DoAll( SetArgPointee<0>( 3 ), Return( 0 ) ) );
//No EXPECT_CALL for the other OMM-function, since that was not expected for this
//particular test
... //other mocks, not interesting for this question
}
TEST_F( fixture, test_case )
{
setup_mocks();
SUT_function_to_be_tested();
}
这意外地导致调用OMM_function_not_interesting_for_this_particular_test而不是OMM_function_interesting_for_this_particular_test。
从上面可以看出,我已经发现它与GoogleMock如何设置模拟有关,因此我提到了更多的全局变量&#39;所以同时我也是将代码更改为:
void setup_mocks( my_arg_type *argument)
{
argument->enummember = NON_ZERO_ENUM_MEMBER;
EXPECT_CALL( *my_mock, MTBM_mock_function( _, _ ) )
.times(1)
.WillOnce( DoAll( SetArgPointee<1>( &*argument ), Return( 0 ) ) );
...
}
TEST_F( fixture, test_case )
{
my_arg_type argument;
setup_mocks( &argument );
SUT_function_to_be_tested();
}
这是有效的,但我想知道是否有办法避免“更全球化”的问题。解决方案并直接通过GoogleMock进行(例如,定义我自己的行动类型(我根本没有任何经验)?)。由于需要在要模拟的许多其他函数中模拟具有指向指针的特定模式,因此需要更多单元测试。我希望将来避免这种情况,我需要创建具有多个参数的setup_mock函数,只是为了设置一些指针到指针的模拟。