在工作中需要做測試,開發是用了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代碼
Set pl = CreateObject("Pt.Point")<br />MsgBox pl.CStr()<br />For Each Item In pl<br /> MsgBox CStr(Item.x)+" "+CStr(Item.y)<br />Next