在工作中需要做测试,开发是用了python,一来语法简单,而来也有robotframework可以配合使用。开发一般用QTP测试比较少,QTP测试也比较慢。所以可以直接使用python开发的库,或者最多提炼一些关键词,用robotframework来做测试也好。
测试方面也针对同样的测试项做了开发,由于终端传递出来的是c数据结构,比较复杂,而用dll调用的方式由于没有跟c很好的接口,导致提取结构非常辛苦,后来想了个办法,用micString+micByRef预先分配好字符串,然后dll库内把数据用sprintf格式化出name=value;这种格式来使用。然后在vbs中再恢复出来,非常辛苦。当然,这些值也可以从页面取到,不过QTP操作页面有时候速度比较慢,没有直接从接口取数据快。
针对这种情况,用python+python win32扩展把python对象封装出来供使用。里面使用了ctypes库,以便于定义c语言的结构,能做到跟c语言布局一样。而且可以定义复杂的数据结构。也很容易在ctypes对象和string之间做pack和unpack。另外,使用了python win32扩展中的win32com.server.util的集合对象,以便于在vbs中使用for each...next结构。 废话不多说了。下面贴出代码
import string
import pythoncom
import pywintypes
import winerror
import types
from ctypes import *
from win32com.server import policy
from win32com.server.util import NewEnum,NewCollection,wrap,unwrap,Collection,ListEnumeratorGateway
from win32com.server.exception import COMException
class myStructure(Structure):
def __str__(self):
s=[]
for k,v in self._fields_:
if type(v)==type(c_int) or type(v)==type(Structure): #SimpleType
s.append("%s=%s"%(k,getattr(self,k)))
elif type(v)==type(Array):
s.append('%s=%s'%(k,'['+','.join(["%s" % getattr(self,k)[i] for i in range(v._length_)])+']'))
else:
pass
return '%s(%s)'%(self.__class__.__name__,','.join([i for i in s]))
class CollectionGateway(Collection):
"A collection which wraps a sequence's items in gateways"
def Item(self, *args):
if len(args) != 1:
raise COMException(scode=winerror.DISP_E_BADPARAMCOUNT)
try:
return wrap(self.data[args[0]])
except IndexError, desc:
raise COMException(scode=winerror.DISP_E_BADINDEX, desc=str(desc))
def _NewEnum(self):
return NewEnum(self.data,ListEnumeratorGateway)
class comPoint(myStructure):
_fields_=[('x',c_int),('y',c_int)]
_public_methods_=[]
_public_attrs_=['x','y']
class comPointList(myStructure,CollectionGateway):
_fields_=[('num',c_int),('list',comPoint * 2)]
_reg_progid_ = "Pt.Point"
_reg_clsid_ = "{CB2E1BC5-D6A5-11D2-852D-204C4F4F5024}"
_public_methods_=['CStr']
_public_attrs_=['num']
def CStr(self):
return str(self)
def Item(self, *args):
if len(args) != 1:
raise COMException(scode=winerror.DISP_E_BADPARAMCOUNT)
try:
return wrap(self.list[args[0]])
except IndexError, desc:
raise COMException(scode=winerror.DISP_E_BADINDEX, desc=str(desc))
def _NewEnum(self):
return NewEnum(self.list,ListEnumeratorGateway)
if __name__=='__main__':
import win32com.server.register
win32com.server.register.UseCommandLine(comPointList)
这里面核心部分是引入了CollectionGateway,这样对每个集合对象在传出的时候都会wrap成com对象。_NewEnum则在For Each的时候被自动调用,当然,也暴露了一个num属性,用于知道有几个元素,另外,用Item也可以直接取对应元素。
下面是测试的vbs代码