写点什么

极光笔记 | 基于 Robotframework 框架进行服务端 SDK 的自动化 (C++ 版本)

作者:极光JIGUANG
  • 2022 年 3 月 09 日
  • 本文字数:2654 字

    阅读完需:约 9 分钟

极光笔记 | 基于Robotframework框架进行服务端SDK的自动化(C++版本)

作者:极光研发中心 高级工程师 —— 成协主


导语


”协主,把 jCache 和 JMQS 的 SDK 自动化用例 robotframework 化。“


某天,收到了这么一个任务。jCache 和 JMQS 是公司自研的存储和消息的中间件,用于对 Redis(包括 pika)和 Rocket MQ 的访问提供统一的接口,并且根据公司的实际业务需要做一些定制化以及相关数据报表的开发。这两个中间件都有提供 SDK 供业务模块来使用,包括针对 C++、Golang 以及 JAVA 这三种 SDK。目前测试人员需要针对这些 SDK 做测试,并且将相关的用例转成自动化用例,自动化用例框架采用 robotframework(后续用 RF 简称)。

今天我们主要是以 jCache 为例,说说其中的 C++ SDK 进行 RF 自动化


一、需求分析


jCache 是针对 Redis 做的中间件开发,提供的接口基本涵盖了 Redis 的所有操作命令,目前有对外提供 100 多个命令接口,而且每个命令接口都包含了同步和异步调用这两类 API。如果 RF 化,需要针对每种 API 都提供 python 版本的调用接口,否则没法通过 RF 框架来直接调用 C++中的 API 接口。


1.1  现有的自动化用例方案


我们之前用的测试框架是 GTest。这个是 google 开源的专门针对 C++测试的框架,但从测试人员的视角来看还是存在一些问题:

  • 代码和数据未分离,使用不同的数据调用相同的代码需要重复编码

  • 有新增用例需要重新编译用例代码

  • 执行输出结果比较简单,只能得到最终的结果,中间的步骤没法跟踪

  • 是一套独立的框架体系,没法和现有的自动化框架体系融合

  • 需要有一定的 C++基础

从上面来看,针对测试人员来讲这套自动化框架的限制还是比较多。


1.2  新的 RF 方案优势


但是如果改成 RF 框架,对于测试人员来讲就友好多了。首先学习成本基本无,大家对于这个东西都比较熟,不管是写用例还是写相关的自定义方法,都是比较熟练的。

相关优势还包括:

  • 测试人员不用关注 C++的 API 到 python 方法之间的转化,屏蔽掉了 C++调用的细节

  • 测试人员可以像使用普通的库一样来调用 jCache SDK 中的函数

  • jCache 的库更新后,可以根据需要更新或者不更新相关的库代码,实现功能的回归或新接口的测试

  • 实现调用逻辑和测试数据的分离


1.3  RF 过程中的挑战


进行 RF 化实际上分为三个步骤:

  • 将 C++ SDK 中的相关 API 函数封装成 so

  • 生成相关的库文件,供 RF 调用

  • 编写相关的 RF 自动化用例

目前最关键是前面 2 个步骤,对 API 函数的封装以及相关库函数的生成。这个其实有点类似于 python 库的开发,只不过一般的 python 库可以供所有人使用,这个是私有的


二、对 C++ SDK 中函数的封装


前面已经说到,针对每种命令,SDK 有提供同步和异步两种多态函数,实际上同步接口还包含了一个开关,提供了对批量命令的支持。如果直接对这些接口进行封装,那么到了 python 代码中,不仅要支持批量的调用,而且还需要对异步回调做处理,将会使得后续的 python 代码复杂化,所以最好的办法对原始的函数做改造,将改造后的函数再封装到 so 中,这样在 python 层面,调用不同的方法名实现对同步、异步以及批量这些类型接口的调用。


2.1  原始接口的改造


我们先对看下原始的函数是怎么样的



这上面是 Set 这个命令的两种调用方式,第一种是同步的调用,其中最后一个参数 batch 来控制是否做批量,其返回参数是一个结构体的智能指针,第二种是异步的调用,其中参数 cb 是回调函数,返回是整型

按照之前的思路,需要将这两个函数拆成 3 个函数。那这 3 个接口的文件如何组织呢?

由于涉及的接口比较多,可以将同样的类型的接口组合成一个新的类,但是这些接口中有些是公共的,比如实例的初始化(也就是和服务端建立连接),以及一些私有的公共变量保存,那么这部分也需要建立一个类来组织,这个公共的类由于被新建的其他 3 个类所引用,在文件组织时可以以这个类为基类。相关的变换关系如下:



其中 jCacheIceClient 是原始的 SDK 头文件,后面 4 个是新建的。


2.2  返回数据的处理


前面可以看到,返回的数据是一个结构体的智能指针,但是在 python 层面,需要的是实际的 string 格式数据,这里就需要对返回的数据进行处理。下面是一段代码供参考:



上面的代码展示了对智能指针的一些基本的处理,重点还是在 get_result 这个函数的处理,这个函数的代码如下:




这部分代码实际上就是将一个结构体的数据放在一个 json 串中,然后返回。

我们这里用到了一个外部库 libjson,这个库可以快速的构建 json 结构的串。


2.3  异步接口的改造


针对异步接口的改造,我们的方法也比较简单,就是在调用层面,直接返回实际数据。

下面是一段异步的返回代码:



和上面的同步接口相差不大,主要是这里多了一个 async_get 函数来获取智能指针,这个函数的执行代码如下:



可以看到,这个函数就是等待 g_resp 这个参数什么时候不为空,不为空就意味着有通过回调返回了数据。回调函数是怎么设置的呢,这里可以看下 AsyncCallback 相关的执行逻辑:




现在就比较清楚了。前面设置一个回调函数获取到回调接口返回的数据,主函数中不断等待这个数据,有数据后就马上返回。由于一般的异步执行很快,这里在实际的执行过程中,可能等待不了几毫秒就很将数据返回了


三、使用 swig 连接 C++和 python 代码


在上面的过程中已经解决了 SDK API 的改造问题,但是这些改造的代码要能够被 python 所使用,还需要将其同 python 连接起来,连接起来的文件就是 so 动态库。

python 其实自身有提供一套连接 C/C++的方法,可以去官方文档查看:https://docs.python.org/2.7/c-api/intro.html

但是你会发现这套文档看起来非常晦涩,涉及到大量的新的对象、类以及方法的应用,而且针对和 C++的结合部分还需要花大精力去学习。有没有一套简单的方法来使用呢?有,这就是 swig。

swig 的官网是http://www.swig.org。swig 是一个连接 C/C++和其他高级语言的开发工具,我们用到的 python 就在其中。

在使用 swig 进行转换之前,需要需要编写后缀为 i 的文件,如:



然后使用 swig 进行 python 化的转换,生成一个带有_wrap 后缀是 cxx 的文件,这个文件和其他的一些 cpp 文件一起编译,就可以得到我们需要的 so 文件。下面是一段编译生成 so 文件的 make 输出:






上面的红色部分就是最后输出的 3 个我们需要的 so 文件。

在 swig 的转换的时候同样会生成一个同名的 python 文件,这个是 python 引用的时候需要用到的。

然后下一步就很明显,我们需要的 so 和相关的引用库已经全部得到,我们只需要引用这个类库,然后就可以将相关的方法全部引用到。

当然这里最好是将相关的方法做一步封装,然后在 RF 脚本中做引用。

全部的过程可以用下面的一张图来阐述:



四、RF 执行

下面是所有的需要的文件的列表,包括我们改造后的 cpp 文件(以及 include 文件),i 格式文件、转换后的 cxx 文件以及 Lib 结尾的引用库文件,当然还包括自己编写的供 RF 调用的以_Sync 结尾(这个是同步)的 py 文件:



相关的用例列表:



这里以同步的用例,查看其执行结果:



用户头像

极光JIGUANG

关注

还未添加个人签名 2021.04.23 加入

还未添加个人简介

评论

发布
暂无评论
极光笔记 | 基于Robotframework框架进行服务端SDK的自动化(C++版本)_c++_极光JIGUANG_InfoQ写作平台