我需要模拟一个函数,它有指针到指针的参数(因此是**参数)。
我尝试了一下下面的伪代码(注意: 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 ) ) );
这是正常的,但是当我运行测试时,argument.enummember是0。
如果我是正确的,这是由于googlemock复制了我想返回的内容,如果是SetArgPointee,则为它创建一个指针(因此,在正常情况下,可以说是SetArgPointee(参数) )。但是在这个例子中,我给出了一个地址,这个地址被转换成一个指针。但是变量的实际值没有存储(如果我的假设是正确的)。
是否有一种标准的方法可以让googlemock处理**参数,还是我必须创建一个更“全局”的变量并返回该变量的地址?
/编辑/将我以前的编辑移至第二次答复,以保持原问题简短
发布于 2014-11-19 01:53:03
如果没有看到更多的代码,我就无法弄清楚argument.enummember是如何变成0的。尽管如此,应该可以使用google模拟将指针设置为指针参数。
从一个简单的类开始(类似于最初文章中提到的内容)。
class argument {
public:
int enummember;
};
然后设置一个模拟类,该类具有一个名为"run“的模拟方法,其参数是指向指针的指针。
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;
发布于 2014-11-20 08:27:50
/编辑/从原来的问题转到这里,以保持原来的问题简短
如果需要更多的信息(我不允许给出确切的代码,所以我必须坚持一个伪实现)。我一开始想避免这种情况,因为(正如你所看到的)它使我的问题很长;-)
@Dan:我看到你的回答基本上可以归结为我的“更全球化”的解决方案,而不是更好的论证;-)。在这一刻,我不会把它设置为“正确的答案”,因为我想看看这个额外的信息是否有一个更好的信息,但只要没有人认为它是正确的答案。
一些背景信息:
注意:由于实际上有两个模块(更多,但对于这个特定问题并不有趣),所以我已经用MTBM_mock_function替换了上面示例中的名称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,其中我指定了夹具的结构)
我的第一次尝试(上述问题所依据的)是:
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如何设置模拟有关,因此我引用了“更多的全局变量”,因此,同时我将代码更改为:
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函数,以便设置许多指针到指针的模拟。
https://stackoverflow.com/questions/26976357
复制相似问题