C++ 如何在google模拟测试中将值设置为模拟方法的void*参数?

C++ 如何在google模拟测试中将值设置为模拟方法的void*参数?,c++,googlemock,C++,Googlemock,我想将字符串“Device Name”传递给方法的void*指针参数,然后将其检索到字符数组 为此,我做了如下所示的工作 在这里,我创造了一个行动来实现这一点 ACTION_P(SetArg2ToChar, value) {*static_cast<char*>(arg2) = *value; } 我的模拟方法 MOCK_METHOD5(getDictItem, bool(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD

我想将字符串“Device Name”传递给方法的
void*
指针参数,然后将其检索到字符数组

为此,我做了如下所示的工作

在这里,我创造了一个行动来实现这一点

ACTION_P(SetArg2ToChar, value) {*static_cast<char*>(arg2) = *value; }
我的模拟方法

  MOCK_METHOD5(getDictItem,
  bool(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD dwLength, CSdo& sdo));
在代码中,它被称为

if( !can.getDictItem(wIndex, bSubIndex, pObjData, dwLength, tSdo) )
我想向这个
pObjData
(列表中的第三个参数)传递一个字符串

在我的谷歌测试中,我就是这样做的

char szDeviceName[30]= {0};
snprintf(szDeviceName, sizeof(szDeviceName), "%s", "Device Name" );

EXPECT_CALL( mockCan, getDictItem(_,_,_,_,_) )
            .WillOnce(DoAll(SetArg2ToChar(szDeviceName),
            Return(true)))
            .RetiresOnSaturation();

/*    Call a real method within which this mock method is called */
如果我试图直接使用“SetArgPointee”设置此参数(pObjData),则会出现以下错误

错误:“void”不是指向对象类型的指针*

因此,我正在尝试
ACTION\u p

现在,在这个实现中,我只得到
szDeviceName
变量的第一个字母(在这个
pObjData
中),即在调用这个模拟对象之后,在实际代码流中,“D”后跟29个0

我想在这个
void*
参数中设置完整的字符串名

我在下面的问题中提到了这个问题,并且能够取得这么大的进展。但是我不能传递完整的字符串


与此相关的任何信息都会有所帮助。

您可以调用函数(或方法)并复制参数,而不是执行此操作

在测试所在的源文件中类似于以下内容:

int invokedPObjData;

bool FakeGetDictItem(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD dwLength, CSdo& sdo)
{
  // copy data. here I assumed it is an int
  invokedPObjData = *static_cast< int* >( pObjData );

  return true; // or whatever makes sense
}

然后在稍后的测试中检查需要检查的内容。

操作方法基本上没有问题。但是,在处理C字符串时,不能只使用赋值操作(只复制第一个字符),而是应该使用字符串复制函数,如
ACTION\P(SetArg2ToCharWithSizeArg3,value){strcpy_s(static_cast(arg2),arg3,value);}
(我忍不住稍微重命名该操作).

我最近也有类似的需求,并提出了一个通用解决方案。它基于内置的
SetArgPointee
,具有相同的语法:

template <size_t N, typename A>
class SetArgumentPointeeVoidAction {
public:
    explicit SetArgumentPointeeVoidAction(const A& value) : value_(value) {}
    void operator=(SetArgumentPointeeVoidAction const&) = delete;

    template <typename Result, typename ArgumentTuple>
    void Perform(const ArgumentTuple& args) const
    {
        ::testing::StaticAssertTypeEq<void, Result>();
        ::testing::StaticAssertTypeEq<void*,
            std::decay<decltype(::testing::get<N>(args))>::type>();
        *static_cast<A*>(::testing::get<N>(args)) = value_;
    }

private:
    const A value_;
};

/**
 * \brief  Sets a \c void* output argument to the contents of the
 *         supplied object.  It's on you to ensure this is safe.
 * \tparam N The argument index.
 * \tparam T The real argument type.
 * \param  x The argument to assign to the output argument.
 * \return A GMock Action that performs the requested assignment.
 * \note   Use \c SetArgPointee when it's not a \c void*.
 */
template <size_t N, typename T>
::testing::PolymorphicAction< SetArgumentPointeeVoidAction<N, T> >
SetArgPointeeVoid(const T& x)
{
    return ::testing::MakePolymorphicAction(
        SetArgumentPointeeVoidAction<N, T>(x));
}
模板
类SetArgumentPointeeVoidAction{
公众:
显式SetArgumentPointeeVoidAction(常量A和值):值{(值){}
void运算符=(SetArgumentPointeeVoidAction常量&)=删除;
模板
void Perform(常量参数元组和参数)常量
{
::测试::StaticAssertTypeEq();
::测试::StaticAssertTypeEq();
*static_cast(::testing::get(args))=value;
}
私人:
常数A值u0;
};
/**
*\brief将\c void*输出参数设置为
*提供的对象。你有责任确保这是安全的。
*\t在参数索引中添加内存。
*\T内存不是真正的参数类型。
*\param x要分配给输出参数的参数。
*\返回执行请求的分配的GMock操作。
*\note在不是\c void*时使用\c SetArgPointee。
*/
模板
::测试::多态性
设置argpointeevoid(常量T&x)
{
return::testing::MakePolymorphicAction(
SetArgumentPointeeVoidAction(x));
}
如果您试图在非
无效*
的参数上使用此选项,则会出现编译错误,因此只要确保提供正确的参数,就应该相对安全

也可以使用
ACTION\u TEMPLATE
来实现这一点,这稍微短一点,但它会生成未使用的参数警告,这可能会令人恼火

(在较旧版本的GMock中,您可能必须使用
::std::tr1::get
而不是
::testing::get


留给读者一个练习:可以通过完美的转发来增强这一点,从而允许移动构造和移动分配,从而略微提高效率。虽然如果您将pod以外的任何内容作为
void*
s传递,那么您可能做得不对。

下面是一个使用操作模板的示例,允许将字符串分配给
void*
,以供参考

ACTION_TEMPLATE(StrCpyArgToVoidPointer,
                HAS_1_TEMPLATE_PARAMS(int, k),
                AND_2_VALUE_PARAMS(value, size))
{
    strncpy(static_cast<char *>(::testing::get<k>(args)), value, size);
    return;
}
ACTION\u模板(StrCpyArgToVoidPointer,
具有_1_模板_参数(int,k),
和_2_值_参数(值、大小))
{
strncpy(static_cast(::testing::get(args)),值,大小);
返回;
}

请找到使用invoke方法在类中设置Void指针变量的步骤

//Actual Function under Test 
void testFunction(void)
{
   uint16 Frequency;
   uint8  PwmId;
   uint8  DutyCycle;

   Frequency = PORTEXTENDER_ZERO;
   PwmId = PORTEXTENDER_ZERO;
   DutyCycle = PORTEXTENDER_ZERO;

//for this mock is available  and we need to set value of Ex. PwmId 
   IncCom_ReceiveSignal(SCC_PORT_EXTENDER_PWM_C_SET_PWM_Id, &PwmId);

  if((PwmId <= PORTEXTENDER_NUM_PWM_CHANNELS) && (DutyCycle <= 100))
  {
  }

 // Actual Defination of mock ..where we have to set void pointer

 void mock_defination(PortExtender_C_SignalId_e SignalId, void* SignalDataPtr)
{

}

//cpp Test class 

class testClass : public :: testing :: Test 
{
           protected:
           /* Fixture tear down */
                      virtual void TearDown()
                      {

                      }

                      uint8 testval1{1};

           public:
                      void setTestvalue(uint8 val) // if we want to set multiple time
                      {
                                 testval1= val;
                      }
                      void test1(PortExtender_C_SignalId_e SignalId, void* SignalDataPtr) //this is method to invoke from test_F
                      {
                                 * (uint8*)SignalDataPtr =testval1;
                      }              
}

//Test Case 
TEST_F(testClass,
testcase_PortExtender_CompStatusResponse_ifConditionSatisfied)
{
setTestvalue(1); //To Set Value 
EXPECT_CALL(m_portExtender_SomeIpMock,m_C_Signal(SCC_PORT_EXTENDER_C_COMPONENT_STATUS_HostApplStat,_))
           .WillOnce(Invoke(this,&testClass::test1));
}
//正在测试的实际函数
void测试函数(void)
{
uint16频率;
uint8-PwmId;
uint8 DutyCycle;
频率=零;
PwmId=0;
DutyCycle=0;
//此模拟可用,我们需要设置Ex.PwmId的值
IncCom_接收信号(SCC_端口_扩展器_PWM_设置_PWM_Id和PwmId);

如果((PwmId我找不到在什么名称空间中调用lives,有什么帮助吗?@Joris我想它是)::测试”
ACTION_TEMPLATE(StrCpyArgToVoidPointer,
                HAS_1_TEMPLATE_PARAMS(int, k),
                AND_2_VALUE_PARAMS(value, size))
{
    strncpy(static_cast<char *>(::testing::get<k>(args)), value, size);
    return;
}
//Actual Function under Test 
void testFunction(void)
{
   uint16 Frequency;
   uint8  PwmId;
   uint8  DutyCycle;

   Frequency = PORTEXTENDER_ZERO;
   PwmId = PORTEXTENDER_ZERO;
   DutyCycle = PORTEXTENDER_ZERO;

//for this mock is available  and we need to set value of Ex. PwmId 
   IncCom_ReceiveSignal(SCC_PORT_EXTENDER_PWM_C_SET_PWM_Id, &PwmId);

  if((PwmId <= PORTEXTENDER_NUM_PWM_CHANNELS) && (DutyCycle <= 100))
  {
  }

 // Actual Defination of mock ..where we have to set void pointer

 void mock_defination(PortExtender_C_SignalId_e SignalId, void* SignalDataPtr)
{

}

//cpp Test class 

class testClass : public :: testing :: Test 
{
           protected:
           /* Fixture tear down */
                      virtual void TearDown()
                      {

                      }

                      uint8 testval1{1};

           public:
                      void setTestvalue(uint8 val) // if we want to set multiple time
                      {
                                 testval1= val;
                      }
                      void test1(PortExtender_C_SignalId_e SignalId, void* SignalDataPtr) //this is method to invoke from test_F
                      {
                                 * (uint8*)SignalDataPtr =testval1;
                      }              
}

//Test Case 
TEST_F(testClass,
testcase_PortExtender_CompStatusResponse_ifConditionSatisfied)
{
setTestvalue(1); //To Set Value 
EXPECT_CALL(m_portExtender_SomeIpMock,m_C_Signal(SCC_PORT_EXTENDER_C_COMPONENT_STATUS_HostApplStat,_))
           .WillOnce(Invoke(this,&testClass::test1));
}