自动化测试中Python与CC的混合使用
自动化测试中Python与C/C++的混合使用
背景
项目的
自动化测试中已经使用了基于 Python
脚本的框架,自动化过程中最关键的问题就是如何实现桩模块。运用
Python
强大的功能,实现任何桩模块都是可能的,但是是否必须完全使用
Python
实现模块逻辑,成本是一个决定性因素。在桩模块逻辑简单的情况下,使用
Python
模拟模块逻辑不但使自动化测试的结构清晰,也具有更好的灵活性,但是如果桩模块逻辑复杂,实现起来可能要耗费很大的成本,也容易由于桩模块逻辑与实际不符导致测试结果不可信。在这种情况下,如果能够借用
RD
开发的某些代码段
/
库,将会对测试自动化带来很多效益。
另外,在 Python
中调用
C/C++
代码的方法也可能应用于
C/C++
库的测试中,这种测试方法的可行性还有待研究。
以下总结出几种在 Python
中调用
C/C++
代码的方法
使用 ctypes
模块调用
C
动态库
从 Python2.5
开始,
Python
开始提供
ctypes
模块来提供对
C
语言编译的动态库文件的调用。注意,
这里特指 C
的动态库
,用 C++
编译的动态库
ctypes
虽然能够加载,但调用时的函数名已经由于
C++
的重载特性被加以修改,难以调用。 使用
ctypes
调用
C
动态库的好处在于不用进行额外的开发,可以直接使用编译好的动态库。
ctypes
提供了完整的
C
类型封装,也支持自定义类型,大大减少在调用过程中的工作量。
ctypes
的使用很简单,只需熟悉
python
封装与
C
中的对应关系即可。以下用一个简单的例子来说明:
from
ctypes
import
#导入ctypes模块
libc = cdll.LoadLibrary(“libc.so.6”)
#加载libc动态库
str
= c_char_p('
Hello World!
‘)
#使用char 在ctypes中的对应封装c_char_p,相当于char str=”Hello World!”
libc.printf(“yell: %s/n”,
str
)
#调用printf函数
ctypes 的功能当然远不止这些,有兴趣的同学可以参考这里
使用 Python
的扩展(
Extending
)机制
ctypes 很方便地可以调用
C
的动态库,但是对
C++
编译的动态库,调用起来很困难。这种情况利用
Python
的
Extending
机制就可以解决。
Python
提供了一套完整的框架来使用
C/C++
编写扩展库,可以很灵活的开发
C++
扩展模块。这种方法的缺点是工作量比较大,需要为每一个方法编写接口,这里不做详细介绍,可以参考:
那么有什么办法可以高效的调用 C++
动态库呢,答案是
SWIG
。
使用 SWIG
生成扩展模块
上面提到了 Python
的扩展机制,缺点是工作量比较大,这里介绍一个工具
SWIG
。
SWIG
是一种简化脚本语言与
C/C++
接口的开发工具,通过包装和编译
C
语言程序来达到与脚本语言通讯目的的工具。它正是基于
Python
的扩展机制,自动生成接口文件,再编译成可以被
Python
调用的动态库扩展模块。
使用 SWIG
生成扩展模块分为以下几步:
将需要调用的代码编译成目标文件 (.o)
用 SWIG
读取编写描述文件
(.i)
,生成接口文件
(.cxx)
;
将接口文件编译为目标文件 (.o)
将接口文件的目标文件和原代码段的目标文件一起编译成动态库
以下举例说明:
假设有如下文件
swig_ex.cpp
需要转换成扩展库的原始代码,包含一个 int fact(int)
函数
swig_ex.h
原始代码的头文件
swig_ex.i
SWIG 描述文件
swig_ex.i 是一个描述文件,有
SWIG
自己的语法,比较简单,内容如下:
%module swig_ex
%{
#define SWIG_FILE_WITH_INIT
#include “swig_ex.h”
%}
int fact(int n);
再写一个 Makefile
来把这些文件编译成动态库
:
all: swig_ex.o swig_ex_wrap.o _swig_ex.so
swig_ex.o: swig_ex.cpp swig_ex.h # 编译源文件
g++ -fPIC -c swig_ex.cpp
swig_ex_wrap.o: swig_ex.i swig_ex.o # 根据
SWIG
描述文件
(.i)
生成接口文件
(.cxx)
,再编译之
swig -c++ -python swig_ex.i
g++ -O2 -fPIC -c swig_ex_wrap.cxx -I/home/work/linyi/autoframe/tool/python/include/python2.6/
_swig_ex.so: swig_ex_wrap.o # 将目标文件打包成动态库
g++ -shared swig_ex.o swig_ex_wrap.o -o _swig_ex.so
.PHONY: clean
clean:
rm -rf swig_ex_wrap.* swig_ex.py _swig_ex.so
编译好以后会有一个 so
和
py
文件,写一个
setup.py
把他们安装到
python
目录就可以和其他模块一样被
python
调用了:
Import swig_ex
swig_ex.fact(10)
参考文档地址:
原始但有效的方法
除了上面这些方法,在 Python
中借用
C/C++
代码最原始有效的方法就是将代码编译成可执行程序,从
Python
里用
Popen
方法来调用获取输出。这种方法简单有效,缺点是不够灵活,有比较大的局限性,不过在很多情况下也已经足够了。
pipe = os.popen(’./tool –a %s –b %s’ % (“hello”, “world”))
re = pipe.read()
其他方法
以上这些方法基本上已经能满足 Python
调用
C/C++
的需求了,此外还有一些方法,例如使用
Boost.Python
,使用
Pyrex
,这些方法都能提供
Python
与
C/C++
的交互。
总结
在 Python
中引用
C/C++
模块的方法较多,根据需要从中选择恰当的方法可以减少很多工作量。
在 Python
中引用
C/C++
模块弥补了
Python
脚本测试框架的很多不足,在提高代码复用率的同时,模块的性能也大大提高。