使用指向指针的参数模拟一个函数

时间:2014-11-17 15:44:03

标签: googlemock

我需要模拟一个具有指针指针参数的函数(因此是一个**参数)。

我尝试了下面的一段伪代码(注意: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是否有一种标准的方式可以处理**参数,或者我是否需要创建一个更全面的“全球”版本。变量并返回该变量的地址?

/ 编辑 /将我之前的编辑内容移至第二个回复以保持原始问题的简短

2 个答案:

答案 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:我看到你的回答基本上归结为我的“更全球化”的问题。解决方案,但比更好的论证;-)。此时我不会将其设置为“正确答案”,因为我想看看是否有更好的信息,但是只要没有人认为这是正确的答案。

一些背景信息:

  • 我测试的代码是plain-C,因此我的模拟使用结构i.s.o.类。
  • my_arg_type 类型在SUT(被测系统)使用的头文件中定义
  • 保持简单:MTBM代表ModuleToBeMocked,OMM代表OtherMockedModule。
  • SUT_code和MTBM / OMM代码是旧的现有代码,我不允许更改(不要修复故障)

注意:由于实际上有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函数,只是为了设置一些指针到指针的模拟。