通过Gtest访问C++静态、私有、保护变量和方法

简介: 通过Gtest访问C++静态、私有、保护变量和方法

1,通常情况

在工作目录主目录下建立目录src

进入src下建立TestAll.cpp测试主文件.

代码语言:javascript

复制

#include "gtest/gtest.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
        testing::GTEST_FLAG(output) = "xml:";     //若要生成xml结果文件
        testing::InitGoogleTest(&argc,argv);      //初始化
        return RUN_ALL_TESTS();                   //跑单元测试
}

建立参数化文件CallArgs.h

代码语言:javascript

复制

//CallArgs.cpp   
#include <gtest/gtest.h>
class CallArgs{
public:
  CallArgs(int haspramx,int hasprama,int haspramb, float hasresult);    
  int pramx();
  int prama();
  int pramb();
  float result();
private:
  int _hasPramx;
  int _hasPrama;
  int _hasPramb;
  float _hasResult; 
};

和CallArgs.cpp

代码语言:javascript

复制

//CallArgs.cpp
#include <gtest/gtest.h>
#include "CallArgs.h"
  CallArgs::CallArgs(int haspramx,int hasprama,int haspramb, float hasresult):
     _hasPramx(haspramx),_hasPrama(hasprama),_hasPramb(haspramb),_hasResult(hasresult){}    
  int CallArgs::pramx(){ return _hasPramx;}
  int CallArgs::prama(){ return _hasPrama;}
  int CallArgs::pramb(){ return _hasPramb;}
  float CallArgs::result(){return _hasResult;}
  int _hasPramx;
  int _hasPrama;
  int _hasPramb;
  float _hasResult;

接下来建立被测文件的头文件process.h

代码语言:javascript

复制

//process.h  
#ifndef PROCESS_H  
#define PROCESS_H  
class Process {  
public:  
    int x;
    Process();
    int process(int a, int b);  
};  
#endif

被测文件很简单,包括类变量x和类函数Process,默认为public。本文通过改变类变量x和类函数Process的属性来介绍如何通过Gtest访问C++静态、私有、保护变量和方法。建立被测文件的实现方法,process.cpp。

代码语言:javascript

复制

#include <stdio.h>
#include "process.h"
int x;
Process::Process(){}
int Process::process(int a, int b){
       if ((a>1) && (b==0)){
              Process::x=Process::x/a; 
       }
       if((a==2) || (Process::x>1)){
              Process::x=Process::x+1; 
       }
       return Process::x;
}

在下面的介绍中process.cpp不会做任何变化。下面来建立gtest的测试代码,processTest.cpp。

代码语言:javascript

复制

// ProcessTest.cpp  
#include "process.h"
#include "../../src/CallArgs.h"   
#include <gtest/gtest.h> 
class ProcessTestWithTestP:public ::testing::TestWithParam
{
};
INSTANTIATE_TEST_CASE_P(VOIP, ProcessTestWithTestP, ::testing::Values(
    CallArgs{1,2,0,1}, 
    CallArgs{0,4,0,0},
    CallArgs{1,2,1,2},
    CallArgs{0,1,1,0}
));
TEST_P(ProcessTestWithTestP,BasicTest){
   CallArgs args = GetParam();
   Process p;
   p.x = args.pramx();
   EXPECT_FLOAT_EQ(p.process(args.prama(),args.pramb()),args.result());    
}

ProcessTestWithTestP为测试类,为了达到被测程序的100%路径覆盖,设计4组测试用例,在Gtest中正好可以使用TEST_P参数化来进行测试。

INSTANTIATE_TEST_CASE_P来初始化这4组测试用例的测试数据。

通过

代码语言:javascript

复制

TEST_P(ProcessTestWithTestP,BasicTest)

来实现。

通过

代码语言:javascript

复制

g++ process.h process.cpp processTest.cpp ../../src/AllTest.cpp ../../src/ CallArgs.cpp.h ../../src/ CallArgs.cpp.cpp -o process -lgtest -lgmock -lpthread -std=c++14

来编译,然后通过

代码语言:javascript

复制

./process

来运行

2,静态变量和静态方法

在下面介绍中如何调用静态变量和静态方法,静态变量和静态方法比较简单,一般直接调用就可以。

2.1静态变量

修改process.h文件。

代码语言:javascript

复制

//process.h  
#ifndef PROCESS_H  
#define PROCESS_H  
extern int x; 
class Process {  
public: 
    Process();
    int process(int a, int b);  
};  
#endif

通过extern int x;将x变为静态全局变量,在测试文件procesTest.cpp,可以直接通过x来访问。

代码语言:javascript

复制

TEST_P(ProcessTestWithTestP,BasicTest){
   CallArgs args = GetParam();
   Process p;
   x = args.pramx();
   EXPECT_FLOAT_EQ(p.process(args.prama(),args.pramb()),args.result());
}

2.2静态方法

修改process.h文件。

代码语言:javascript

复制

//process.h  
#ifndef PROCESS_H      
#define PROCESS_H  
extern int x; 
class Process {  
public: 
    Process();
    static int process(int a, int b);  
};  
#endif

通过static int process(int a, int b);将process(int a, int b)变为静态方法,在测试文件procesTest.cpp,仍旧通过p.process()来访问。

代码语言:javascript

复制

TEST_P(ProcessTestWithTestP,BasicTest){
   CallArgs args = GetParam();
   Process p;
   x = args.pramx();
   EXPECT_FLOAT_EQ(p.process(args.prama(),args.pramb()),args.result());
}

3,保护变量和保护方法

保护变量和保护方法,在测试文件procesTest.cpp定义class ProcessTest类的时候将继承的Process类改为public属性。

3.1保护变量

修改process.h文件。

代码语言:javascript

复制

//process.h  
#ifndef PROCESS_H  
#define PROCESS_H  
class Process {  
public: 
    Process();
    int process(int a, int b);  
protected: 
    int x;
};  
#endif

将int x;放在protected下,在测试文件procesTest.cpp定义class ProcessTest类的时候将继承的Process类改为public属性。

代码语言:javascript

复制

class ProcessTest : public ::testing::TestWithParam, public Process{
};

然后在测试文件中直接使用x和process()方法。

代码语言:javascript

复制

class ProcessTest : public ::testing::TestWithParam, public Process{    
};
TEST_P(ProcessTest,BasicTest){
   CallArgs args = GetParam();
   x = args.pramx();
   EXPECT_FLOAT_EQ(process(args.prama(),args.pramb()),args.result());
}

3.2保护方法

修改process.h文件。

代码语言:javascript

复制

//process.h  
#ifndef PROCESS_H  
#define PROCESS_H  
class Process {  
public: 
    int x;
    Process();
protected: 
    int process(int a, int b);  
};  
#endif

将int process(int a, int b);放在protected下,同样在测试文件procesTest.cpp定义class ProcessTest类的时候将继承的Process类改为public属性。

代码语言:javascript

复制

class ProcessTest : public ::testing::TestWithParam, public Process{
};
TEST_P(ProcessTest,BasicTest){
   CallArgs args = GetParam();
   x = args.pramx();
   EXPECT_FLOAT_EQ(process(args.prama(),args.pramb()),args.result());
}

4,私有变量和私有方法

访问私有变量和私有方法比较复杂,不太推荐,因为它会破坏类的封装。但是实现方法基本相同。

1)在被测类头文件中加入:

代码语言:javascript

复制

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

2)在被测类头文件中预先声明被测类

代码语言:javascript

复制

class 被测类;

3)在被测类头文件中类定义中加入

代码语言:javascript

复制

FRIEND_TEST(被测类, TEST_P);

4)在测试类文件processTest.cpp开始加入:

代码语言:javascript

复制

#include: <cstddef>:定义常用常量

5)在测试类文件processTest.cpp中将测试类定义为保护属性。

代码语言:javascript

复制

class ProcessTest : public ::testing::TestWithParam,protected Process{
};

6)使用第3)步定义的测试方法

代码语言:javascript

复制

TEST_P(被测类, TEST_P)

4.1私有变量

修改process.h文件。

代码语言:javascript

复制

//process.h  
#ifndef PROCESS_H  
#define PROCESS_H 
#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test 
class ProcessTest;  
class Process {  
public: 
    Process();
    int process(int a, int b);    
private: 
    int x;
    FRIEND_TEST(ProcessTest, TEST_P);
};  
#endif

将int x放在private下

修改processTest.cpp文件

代码语言:javascript

复制

//ProcessTest.cpp  
#include "process.h" 
#include "../../../src/CallArgs.h"  
#include <gtest/gtest.h> 
#include <cstddef>
class ProcessTest : public ::testing::TestWithParam,protected Process{
};
INSTANTIATE_TEST_CASE_P(VOIP, ProcessTest, testing::Values(
    CallArgs{1,2,0,1}, 
    CallArgs{0,4,0,0},
    CallArgs{1,2,1,2},
    CallArgs{0,1,1,0}    
));
TEST_P(ProcessTest, TEST_P){
   CallArgs args = GetParam();
   Process p;
   p.x = args.pramx();
   EXPECT_FLOAT_EQ(p.process(args.prama(),args.pramb()),args.result());
}

4.2私有方法

修改process.h文件

代码语言:javascript

复制

//process.h  
#ifndef PROCESS_H  
#define PROCESS_H 
#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test 
class ProcessTest;  
class Process {  
public:     
    Process();
    int x;
private: 
    int process(int a, int b);
    FRIEND_TEST(ProcessTest, TEST_P);
};  
#endif

将int process(int a, int b);放在private下

修改processTest.cpp文件同私有变量。

代码语言:javascript

复制

//ProcessTest.cpp  
#include "process.h"  
#include "../../../src/CallArgs.h" 
#include <gtest/gtest.h> 
#include <cstddef>
class ProcessTest : public ::testing::TestWithParam,protected Process{
};
INSTANTIATE_TEST_CASE_P(VOIP, ProcessTest, testing::Values(
    CallArgs{1,2,0,1},     
    CallArgs{0,4,0,0},
    CallArgs{1,2,1,2},
    CallArgs{0,1,1,0}
));
TEST_P(ProcessTest, TEST_P){
   CallArgs args = GetParam();
   Process p;
   p.x = args.pramx();
   EXPECT_FLOAT_EQ(p.process(args.prama(),args.pramb()),args.result());
}

另外,还可以通过公共接口类来访问私有和保护对象和方法。

5,通过公共接口类来访问私有和保护对象和方法

5.1 通过公共接口类来访问私有对象和方法

MyClass.h

代码语言:javascript

复制

// MyClass.h
class MyClass {
private:
    int value;
    void Increment() { // 私有方法    
        value++;
    }
public:
    MyClass() : value(0) {}
    void PerformIncrement() { // 公共方法
        Increment();
    }
    int GetValue() const { // 公共方法,用于获取私有成员的值
        return value;
    }
};

MyClass.h定义了私有类value和私有方法Increment()。

通过公共方法PerformIncrement()来调用私有方法Increment();

通过公共方法GetValue()来获取私有成员value的值。

建立测试程序MyClassTest.cpp

代码语言:javascript

复制

// MyClassTest.cpp
#include "MyClass.h"
#include
TEST(MyClassTest, IncrementTest) {
    MyClass obj;
    obj.PerformIncrement(); // 调用公共方法来间接调用私有方法    
    EXPECT_EQ(1, obj.GetValue()); // 验证私有方法的行为
}

5.2通过公共接口类来访问保护对象和方法

同样也可以通过公共接口类来访问保护对象和方法。

代码语言:javascript

复制

// MyClass.h
class MyClass {
protected:
    int value;
    void ProtectedMethod() { // 保护方法
        value = 42;
    }
public:
    MyClass() : value(0) {}
    void CallProtectedMethod() { // 公共方法,调用保护方法
        ProtectedMethod();
    }
    int GetValue() const { // 公共方法,用于获取保护成员的值
        return value;
    }
};

MyClass.h定义了int value;保护变量和void ProtectedMethod()保护方法。    

通过公共方法CallProtectedMethod()调用保护方法;

通过公共方法GetValue()获取保护成员的值。

建立测试程序MyClassTest.cpp

代码语言:javascript

复制

//MyClassTest.cpp
#include "MyClass.h"
#include
TEST(MyClassTest, ProtectedMethodTest) {
    MyClass obj;
    obj.CallProtectedMethod(); // 调用公共方法来间接调用保护方法
    EXPECT_EQ(42, obj.GetValue()); // 验证保护方法的行为
}

这里介绍了如何通过Gtest访问C++静态、私有、保护变量和方法,下一节将介绍如何通过JUnit访问Java静态、私有、保护变量和方法。

目录
相关文章
|
9天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
32 4
|
2月前
|
编译器 API C语言
超级好用的C++实用库之跨平台实用方法
超级好用的C++实用库之跨平台实用方法
39 6
|
1月前
|
C语言 C++
实现两个变量值的互换[C语言和C++的区别]
实现两个变量值的互换[C语言和C++的区别]
19 0
|
3月前
|
存储 安全 C++
C++:指针引用普通变量适用场景
指针和引用都是C++提供的强大工具,它们在不同的场景下发挥着不可或缺的作用。了解两者的特点及适用场景,可以帮助开发者编写出更加高效、可读性更强的代码。在实际开发中,合理选择使用指针或引用是提高编程技巧的关键。
33 1
|
3月前
|
C++
C++ 避免多重定义的方法
C++ 避免多重定义的方法
60 0
|
3月前
|
Dart API C语言
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
|
5月前
|
安全 C++
C++一分钟之-互斥锁与条件变量
【6月更文挑战第26天】在C++并发编程中,`std::mutex`提供互斥访问,防止数据竞争,而`std::condition_variable`用于线程间的同步协调。通过`lock_guard`和`unique_lock`防止忘记解锁,避免死锁。条件变量需配合锁使用,确保在正确条件下唤醒线程,注意虚假唤醒和无条件通知。生产者-消费者模型展示了它们的应用。正确使用这些工具能解决同步问题,提升并发性能和可靠性。
63 4
|
5月前
|
程序员 编译器 C++
探索C++语言宝库:解锁基础知识与实用技能(类型变量+条件循环+函数模块+OOP+异常处理)
探索C++语言宝库:解锁基础知识与实用技能(类型变量+条件循环+函数模块+OOP+异常处理)
47 0
|
8天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
34 4
|
1月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
27 4