C语言 程序设计 iis ftp sas Ractivejs jq去除空格 docker导入镜像 python用什么ide python命令大全 java中class java目录 qtp下载 win10有哪些版本 王者荣耀自动刷冒险 音乐狂app iframe跨域 威纶通触摸屏编程软件 服务器文件共享软件 服务器之家 renderto 文件粉碎工具 红米手机怎么连接电脑 文字图片制作 ps反选 nastran lol修改皮肤 易语言皮肤模块 python编译 jdk8安装教程 wps求和 aecc2018 中国移动光猫设置方法 project2016中文版下载 仓库管理软件免费版 qq最新版官方下载 maya玻璃材质 js正则 碎手氏族 苹果手机内存怎么看
当前位置: 首页 > 学习教程  > 编程语言

完成自己的Google测试框架

2021/1/13 19:41:47 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

文章目录预备知识预处理命令预定义的宏彩色打印C中的特殊符号C字符串的连接形式C attribute 关键字谷歌C单元测试框架 gTest封装颜色属性LOG函数EXPECT_XX 函数RUN_ALL_TESTS 函数TEST 函数预备知识 预处理命令 在C/C语言中,以#号开头的命令称为预处理命令&#x…

文章目录

  • 预备知识
    • 预处理命令
    • 预定义的宏
    • 彩色打印
    • C++中的特殊符号
    • C++字符串的连接形式
    • C++ attribute 关键字
  • 谷歌C++单元测试框架 gTest
  • 封装颜色属性
  • LOG函数
  • EXPECT_XX 函数
  • RUN_ALL_TESTS 函数
  • TEST 函数


预备知识

预处理命令

在C/C++语言中,以#号开头的命令称为预处理命令,在预处理阶段会进行头文件展开/宏替换/去掉注释/条件编译。常用命令有:
在这里插入图片描述

条件式编译就是对代码进行裁剪,用来决定是否进行编译:#ifdef#ifndef#if #elif #else#endif

预定义的宏

预定义宏是事先已经定义好的宏:

  • 无需定义,就只可以直接使用
  • 预定义宏没有参数,且不可被重定义

预定义宏可以为代码编写提供便利,可以用来输出日期、时间、文件名、函数名等。

在这里插入图片描述

彩色打印

只有Linux系统命令行支持彩色打印

\ 033[ 0 ; A 1 ; A 2 ; . . . ; A n m + t e x t + \backslash \textbf{033[} 0; A_1;A_2;...;A_n \textbf m +text + \033[0;A1;A2;...;Anm+text+

  • 声明变色前缀\033[:转义序列是以 ESC 字符\e开头, 其ASCII 码十进制为27,八进制为 \033
  • 重置属性 0;
  • 中间是颜色属性 A1;A2;...An,其中An是一个0到100的整数,其意义也就是不同的颜色阈值,推荐大家用30到37这个区间的值,因为其对应的颜色依次为灰色、红色、绿色、黄色、蓝色、紫色、天蓝色、白色。大家最后在想要的颜色作用区域结尾加上”\e[37m”
  • 结尾是 m
  • + 变色内容 text
  • 重置属性 \033[0m

示例:

printf("\033[0;33mHello World!\033[0m");

属性列表:
在这里插入图片描述

C++中的特殊符号

  • ... 代表接受可变参数,必须放在最后一个形参的位置上,比如会在catch(...)中遇到
  • # 将宏参数 不经扩展地 转换成字符串常量,宏定义参数左右两边的空格会被忽略,参数的各个Token之间的多个空格会被转换成一个空格;宏定义参数中含有需要特殊含义的字符如"\时,它们前面会自动被加上转义字符\
#include <iostream>
using namespace std;

#define A 123
#define B "bbb"
#define FUNC1(arg)  #arg     // 都转换为原样字符串
#define FUNC2(arg)  FUNC1(arg)

int main() {
	printf("%d", A); // 123
	printf(B); // bbb
	printf(FUNC1(A B));  // A B
	printf(FUNC2(A B));  // 123 "bbb"
	return 0;
}
  • ## 标记连接,将多个Token连接成一个Token,不能是宏定义中的第一个或最后一个Token

https://blog.csdn.net/chinabinlang/article/details/79137941

#include <stdio.h>
#define paster( n ) printf_s( "token" #n " = %d", token##n )
int token9 = 100;
 
int main(){
   paster(9); // 输出 token9 = 100
}
// 编译器解析
paster(9);
printf_s( "token" #9 " = %d", token##9 );
printf_s( "token" "9" " = %d", token9 );
printf_s( "token9 = %d", token9 );

相当于

#define CAT(a, b)  a##b

printf(CAT(token, 9)); // 100,即 printf(token9);

C++字符串的连接形式

下述定义都是等价的,两个字符串是可以用0或多个空格来连接的:

const char* p1 = "Hello," "World!";     // 一个空格  
const char* p2 = "Hello,"    "World!";  // 多个空格  
const char* p3 = "Hello,""World!";      // 没有空格  
const char* p4 = "Hello,World!";        // 一个整串  

C++ attribute 关键字

GNU C的一大特色(却不被初学者所知)就是attribute机制,__attribute__关键字可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute),前后都有两个下划线,后面紧跟原括弧,括弧里面是相应的attribute参数,需要放于声明的尾部“;”之前。

__attribute__((attribute-list)) 
void function();

可设置的属性有:

  • noreturn 函数不会返回
  • alias(“__centon”) 设置函数别名
  • constructor 构造器,在main函数进入前自动调用
  • destructor 析构器,在main函数退出后自动调用
  • noinline 不能作为内联函数优化
    其他属性参见:https://blog.csdn.net/qq_30968657/article/details/55049341

谷歌C++单元测试框架 gTest

https://www.cnblogs.com/jycboy/p/6057677.html

#include gtest/gtest.h

封装颜色属性

#define RED(msg)      "\033[0;1;31m" msg "\033[0m"
#define GREEN(msg)    "\033[0;1;32m" msg "\033[0m"
#define YELLOW(msg)   "\033[0;1;33m" msg "\033[0m"
#define BLUE(msg)     "\033[0;1;34m" msg "\033[0m"

含有重复代码,可以进一步简化,其中 #code 将数值类型转换为了原样的字符串

#define COLOR(msg, code)  "\033[0;1;" #code "m" msg "\033[0m"
#define RED(msg)      COLOR(msg, 31)
#define GREEN(msg)    COLOR(msg, 32)
#define YELLOW(msg)   COLOR(msg, 33)
#define BLUE(msg)     COLOR(msg, 34)

LOG函数

彩色输出当前行号,文件名,函数名等,其中

  • arg...是变参列表,长度不定,可以为0
  • ##args 可以避免空参数导致的 printf 报错
#define LOG(frm, arg...){ \
    printf("\033[0;33m[%s : %s : %d] \033[0m", __FILE__, __function__, __LINE__);\
    printf(frm, ##args); \
    printf("\n"); \
}

开发版本和上线版本的主要区别就是屏蔽了调试信息的输出。如何快速屏蔽LOG宏的输出?

方法一:取消LOG宏,重新定义LOG宏为空

#undef LOG
#define LOG(frm, arg...) 

方法二:使用条件式编译

#ifdef DEBUG
#define LOG(frm, arg...){ \
    printf("\033[0;33m[%s : %s : %d] \033[0m", __FILE__, __function__, __LINE__);\
    printf(frm, ##args); \
    printf("\n"); \
}
#else
#define LOG(frm, arg...) 
#endif

而这个DEBUG宏不只是能在代码中定义,还可以在编译器中定义:

g++  -DDEBUG main.cpp

其中-D就是用来传入宏定义的。

因此,不需要修改源代码即可得到不同的执行结果,也就是说,决定可执行程序功能的不是源代码,而是经过预处理阶段后生成的待编译源码。

EXPECT_XX 函数

#pragma once
#define EXPECT(a, comp, b) { \
	if(!((a) comp (b))){ \
		printf(YELLOW("  %s:%d: Failure\n"), __FILE__, __LINE__); \
		printf(YELLOW("  Expected: (%s) %s (%s), actual: %d vs %d\n"), #a, #comp, #b, a, b); \
		printf("error\n"); \
	}\
}

#define EXPECT_EQ(a, b)   EXPECT(a, ==, b)
#define EXPECT_NE(a, b)   EXPECT(a, !=, b)
#define EXPECT_LT(a, b)   EXPECT(a,  <, b)
#define EXPECT_LE(a, b)   EXPECT(a, <=, b)
#define EXPECT_GT(a, b)   EXPECT(a,  >, b)
#define EXPECT_GE(a, b)   EXPECT(a, >=, b)

RUN_ALL_TESTS 函数

功能:遍历所有测试用例,并运行。
这就需要有注册机制,将所有测试用例的函数地址存储起来。

struct{
	void (*func)();
	const char *func_name; 
} func_arr[100];

int func_cnt = 0;

void add_test_func(void (*func)(), const char *str){
	func_arr[func_cnt].func = func;
	func_arr[func_cnt].func_name = str;
	func_cnt++;
	return;
}

遍历:

int RUN_ALL_TESTS(){
	for(int i=0; i<func_cnt; i++){
		printf(GREEN("[  RUN    ]") "%s", func_arr[i].func_name);
		func_arr[i].func();
	}
}

TEST 函数

#define TEST(a, b) \
void gTest_##a_##b(); \
__attribute__((constructor)) \
void reg_##a_##b(){ \
	add_test_func(gTest_##a_##b, #a "." #b); \
}\
void gTest_##a_##b()

本文链接: http://www.dtmao.cc/news_show_600154.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?