Google Test(GTest) protect保护/私有private属性代码测试技术

2 篇文章 0 订阅

      对于算法项目,基本都是被调用方,像mlr是以动态链接库的形式被isearch调用,那mlr模块暴露的公共接口是针对isearch,但对mlr的测试不仅仅是靠这些公共接口就够的,因为其本身的很多逻辑都是在私有的,这就需要我们有时候对其私有方法和成员进行测试。

      下面有几种打开私有成员和方法的一些办法:

1.加宏编译

      即在你需要打开私有的头文件中加入#define private public/protect

      蛮暴力的,当然也是最容易操作和简单的。

2.利用Gtest的FRIEND_TEST()

Private class members are only accessible from within the class or by friends. To access a class' private members, you can declare your test fixture as a friend to the class and define accessors in your fixture. Tests using the fixture can then access the private members of your production class via the accessors in the fixture. Note that even though your fixture is a friend to your production class, your tests are not automatically friends to it, as they are technically defined in sub-classes of the fixture.

FRIEND_TEST(TestCaseName, TestName);

      上面是gtest的关于私有成员测试wiki介绍,gtest会通过FRIEND_TEST(TestCaseName, TestName)声明了友元,即TestCaseName为友元类,而TestName为具体的case名。

下面用一个例子来简单说明下用法:

假如原类为:

在这个类中foo_e是私有函数,如何通过gtest对其进行测试呢?

对于被测代码,加入gtest相应的头文件和用FRIEND_TEST()来声明友元:

 

gtest测试代码:

 

      对gtest有无fixture,这种方式都是适用的。另外需要注意gtest代码中TEST_F()后面跟的测试类和case名一定要和被测类中FRIEND_TEST()声明的一致,像上面的例子中FRIEND_TEST(ATest1,notfixture)和TEST(ATest1,notfixture)对应的。

      缺点是:往被测代码中添加了测试代码;另外当你对私有成员测试的case很多时,就需要你在被测代码添加多个的FRIEND_TEST(),或者在你的测试代码中,把多个case放在一个TEST_F()中去。

      优点是:对私有成员的打开和测试,代码使用规范,可读性好。即使版本升级,可以通过我们的测试代码中TEST_F()来打开被测代码相应的私有成员。

3、利用pimpl重构被测代码

Pimpl主要的作用是解开代码调用接口和具体实现的耦合,具体的实现大家有兴趣可以自己网上看下。利用这种方式打开私有成员,思路是先对被测代码按照pimpl模式进行重构,把具体实现的私有成员全部放到另外一个辅助类,通过指针访问实现的私有成员,然后对这个辅助类进行原类的私有成员测试。

原被测类:

 

重构后的MyClass为:

 

具体实现为:

 

      经过上面的处理,我们调用新的MyClass类,就可以访问之前的私有成员了,My_Private_Method()对应原来的Private_Method(),My_Private_Class_method()对应原MyClass私有类Private_Class的method()。我们也就可以通过调用新的MyClass来访问其原私有成员,及对其测试了。

      此方法原理简单,实现比较复杂。如果采用此方法,需要开发编码时就采用该模式,或者提测后人工的对其代码进行重构,工作量比较大。

 

另外

      有些时候,我们不仅要测试类暴露出来的公有方法,还要测试其受保护的或者私有方法。GTest测试框架提供了一种方法,让我们可以测试类的私有方法。但是这是一种侵入式的,会破坏原来代码的结构,所以我觉得还是谨慎使用。(转载请指明出于breaksoftware的csdn博客)

        我们先看个例子

// This class has a private member we want to test.  We will test it
// both in a TEST and in a TEST_F.
class Foo {
 public:
  Foo() {}
 
 private:
  int Bar() const { return 1; }
 
  // Declares the friend tests that can access the private member
  // Bar().
  FRIEND_TEST(FRIEND_TEST_Test, TEST);
  FRIEND_TEST(FRIEND_TEST_Test2, TEST_F);
};
 
// Tests that the FRIEND_TEST declaration allows a TEST to access a
// class's private members.  This should compile.
TEST(FRIEND_TEST_Test, TEST) {
  ASSERT_EQ(1, Foo().Bar());
}
 
// The fixture needed to test using FRIEND_TEST with TEST_F.
class FRIEND_TEST_Test2 : public Test {
 protected:
  Foo foo;
};
 
// Tests that the FRIEND_TEST declaration allows a TEST_F to access a
// class's private members.  This should compile.
TEST_F(FRIEND_TEST_Test2, TEST_F) {
  ASSERT_EQ(1, foo.Bar());
}


        Foo类拥有一个名叫Bar的私有成员函数。我们需要通过FRIEND_TEST宏来新增该类的友元类(其实也能想象出来,就是通过友元类来访问私有成员,所以这是一种侵入式的——修改了原来类的结构)

#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test


        上例中给了两种访问私有变量的方式:

  1.      一种是FRIEND_TEST(FRIEND_TEST_Test, TEST);声明的类,然后通过TEST(FRIEND_TEST_Test, TEST)实现测试特例实体,于是该实体中需要使用Foo的构造函数构造一个对象,然后调用其私有的Bar方法。
  2. 一种是FRIEND_TEST(FRIEND_TEST_Test2, TEST_F);声明的类。它使用到了Test Fixtures技术(详见《Google Test(GTest)使用方法和源码解析——预处理技术分析和应用》)。在FRIEND_TEST_Test2类中,声明了一个Foo对象。然后TEST_F(FRIEND_TEST_Test2, TEST_F)类直接使用了该成员变量调用Bar方法。TEST_F(FRIEND_TEST_Test2, TEST_F)既继承于FRIEND_TEST_Test2,又是Foo的友元类。

        这块技术没有什么深奥的,大家只要是知道它是通过友元特性实现,是一种侵入式测试就行了。

 

参考:

https://www.cnblogs.com/baochun968/archive/2012/05/03/2480144.html
https://blog.csdn.net/breaksoftware/article/details/51059572 

https://blog.csdn.net/yasi_xi/article/details/8719952

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值