未调用 Gmock const 方法,而是调用原始方法
Gmock const method not called instead calling the original method
我的接口定义为
在 .h 文件中
namespace diagnostic{
class class1interface{
virtual int readpowerstate()const =0;
virtual int readparameters() = 0;
}
class class1 : public class1interface{
int readpowerstate()const;
int readparameters();}};
在 .cc 文件中我有函数
int diagnostic::readparameters(){
if(diagnostic::readpowerstate ==1)
{ //Dothis}
else
{return 0}}
我必须执行 else 部分,因为默认情况下 if 将在我 运行 程序时被调用。所以我尝试如下使用 gmock。
class Mock_class : public diagnostic::class1interface{
public:
Mock_class(){}
MOCK_METHOD0(readparameters,int());
MOCK_CONST_METHOD0(readpowerstate,int());};
和我写的gmock测试如下
// 测试读取参数失败
TEST_F(TestBase, readParam_failure){
Mock_class mock_class;
class1 *class_dummmy = new class1();
EXPECT_CALL(mock_class, readpowerstate()).WillOnce(Return(0));
class_dummy->readparameters;
EXPECT_EQ(0, class_dummy->readparameters());}
当我执行这个程序时,我得到的错误是
错误:实际函数调用计数不匹配
EXPECT_CALL(mock_class, readpowerstate())
...
预期:至少被调用一次
实际:从未致电 - 不满意且活跃
因为我是 gmock 的新手,所以解决这个问题的方法是什么。
模块测试都是关于在模拟环境中测试一个孤立的模块(如选定 class 的一个实例),特别是该模块如何与其他对象通信,以及它如何响应各种结果这些电话。为了实现这一点,可以使用 mocks 代替其他 real 对象。 Mock classes 允许:
- 配置预期,例如,amount/sequence 调用 and/or 这些对特定函数的调用的参数值,并通过注册所有交互来验证这些;
- 对这些预期调用的结果进行编程,这些调用的结果 return 就好像一个真实的对象执行了一些操作并对被测对象做出了响应。
这使得测试一个对象成为可能,就像它被真实的组件包围一样,而实际上没有这些组件。例如,可以测试设备管理器如何响应设备故障,方法是模拟 class 表示设备和编程,当管理器调用某些状态函数时模拟 return 错误代码。也就是说,没有使用真正的 device class,也不需要连接真正的(错误的!)device 本身并配置。模拟将假装是那个设备,重要的是,这一切都在软件层面。
然而,只有当 class 本身的设计方式允许我们以某种方式 注入 模拟对象来代替它们的真实对象时,这才有可能。最重要的是,系统中的对象需要通过接口和虚拟调用进行通信。也就是说,上述设备管理器不应与 DeviceA
(具体的 class 名称)等进行通信,而是与某些 DeviceInterface
进行通信,因此 DeviceA
和新创建的模拟 DeviceMock
可以实现该接口并在该管理器中使用。这样管理器甚至不知道它正在接受测试并与模拟对象通信,而不是真正的设备包装器。
也就是说,目前,虽然您为 class1interface
创建了一个模拟,但您实际上并没有使用该模拟。相反,您尝试测试 class1
。仅当您旨在测试通过 class1interface
,而不是 class1
本身。
所以,有一个 class1
的模拟,你可以,例如测试 class2
。但这需要这个 class 设计满足我之前提到的条件:通过接口进行通信并能够注入模拟 class.
所以要满足条件,你必须重写代码:
int class2::readdata()
{
std::unique_ptr<diagnostic::class1interface> classint
= std::make_unique<diagnostic::class1>();
int value = classint->readparameters();
return value;
}
至(这只是一个有用性有问题的例子,您必须根据自己的需要进行调整):
int class2::readdata(diagnostic::classinterface* classint)
{
int value = classint->readparameters();
return value;
}
因此您可以为 class2
编写测试,注入 class1
:
的模拟
TEST_F( TestClass2, readParam_failure )
{
// Mocks configuration
Mock_class mock_class;
EXPECT_CALL( mock_class, readparameters() ).WillOnce(Return(0));
// System under test configuration
diagnostic::class2 sut;
// Test itself
EXPECT_EQ( 0, sut.readdata(&mock_class) );
}
通过这种方式,您可以检查对 class2::readdata
的调用是否正确转发到 class1interface::readparameters
,其结果是 returned。
我的接口定义为 在 .h 文件中
namespace diagnostic{
class class1interface{
virtual int readpowerstate()const =0;
virtual int readparameters() = 0;
}
class class1 : public class1interface{
int readpowerstate()const;
int readparameters();}};
在 .cc 文件中我有函数
int diagnostic::readparameters(){
if(diagnostic::readpowerstate ==1)
{ //Dothis}
else
{return 0}}
我必须执行 else 部分,因为默认情况下 if 将在我 运行 程序时被调用。所以我尝试如下使用 gmock。
class Mock_class : public diagnostic::class1interface{
public:
Mock_class(){}
MOCK_METHOD0(readparameters,int());
MOCK_CONST_METHOD0(readpowerstate,int());};
和我写的gmock测试如下 // 测试读取参数失败
TEST_F(TestBase, readParam_failure){
Mock_class mock_class;
class1 *class_dummmy = new class1();
EXPECT_CALL(mock_class, readpowerstate()).WillOnce(Return(0));
class_dummy->readparameters;
EXPECT_EQ(0, class_dummy->readparameters());}
当我执行这个程序时,我得到的错误是
错误:实际函数调用计数不匹配
EXPECT_CALL(mock_class, readpowerstate())
...
预期:至少被调用一次
实际:从未致电 - 不满意且活跃
因为我是 gmock 的新手,所以解决这个问题的方法是什么。
模块测试都是关于在模拟环境中测试一个孤立的模块(如选定 class 的一个实例),特别是该模块如何与其他对象通信,以及它如何响应各种结果这些电话。为了实现这一点,可以使用 mocks 代替其他 real 对象。 Mock classes 允许:
- 配置预期,例如,amount/sequence 调用 and/or 这些对特定函数的调用的参数值,并通过注册所有交互来验证这些;
- 对这些预期调用的结果进行编程,这些调用的结果 return 就好像一个真实的对象执行了一些操作并对被测对象做出了响应。
这使得测试一个对象成为可能,就像它被真实的组件包围一样,而实际上没有这些组件。例如,可以测试设备管理器如何响应设备故障,方法是模拟 class 表示设备和编程,当管理器调用某些状态函数时模拟 return 错误代码。也就是说,没有使用真正的 device class,也不需要连接真正的(错误的!)device 本身并配置。模拟将假装是那个设备,重要的是,这一切都在软件层面。
然而,只有当 class 本身的设计方式允许我们以某种方式 注入 模拟对象来代替它们的真实对象时,这才有可能。最重要的是,系统中的对象需要通过接口和虚拟调用进行通信。也就是说,上述设备管理器不应与 DeviceA
(具体的 class 名称)等进行通信,而是与某些 DeviceInterface
进行通信,因此 DeviceA
和新创建的模拟 DeviceMock
可以实现该接口并在该管理器中使用。这样管理器甚至不知道它正在接受测试并与模拟对象通信,而不是真正的设备包装器。
也就是说,目前,虽然您为 class1interface
创建了一个模拟,但您实际上并没有使用该模拟。相反,您尝试测试 class1
。仅当您旨在测试通过 class1interface
,而不是 class1
本身。
所以,有一个 class1
的模拟,你可以,例如测试 class2
。但这需要这个 class 设计满足我之前提到的条件:通过接口进行通信并能够注入模拟 class.
所以要满足条件,你必须重写代码:
int class2::readdata()
{
std::unique_ptr<diagnostic::class1interface> classint
= std::make_unique<diagnostic::class1>();
int value = classint->readparameters();
return value;
}
至(这只是一个有用性有问题的例子,您必须根据自己的需要进行调整):
int class2::readdata(diagnostic::classinterface* classint)
{
int value = classint->readparameters();
return value;
}
因此您可以为 class2
编写测试,注入 class1
:
TEST_F( TestClass2, readParam_failure )
{
// Mocks configuration
Mock_class mock_class;
EXPECT_CALL( mock_class, readparameters() ).WillOnce(Return(0));
// System under test configuration
diagnostic::class2 sut;
// Test itself
EXPECT_EQ( 0, sut.readdata(&mock_class) );
}
通过这种方式,您可以检查对 class2::readdata
的调用是否正确转发到 class1interface::readparameters
,其结果是 returned。