使用python进行windows自动化测试

最近开始学习整理python在windows自动化测试中的使用,觉得挺有意思的

主要思路,在windows下,主要通过启进程,然后查找进程的句柄,然后再操作这个句柄,包括点击,填写文字,关闭,获取文字等操作

下面以一个简单的校验文件md5值的操作来介绍一个python的应用,当然python中有校验md5的函数,不用非要使用工具来校验,这里只是练习使用python来自动化操作

所用的工具有SpyLite,用于查看窗口ID,句柄等信息

工具下载

http://www.xiazaiba.com/html/358.html

http://www.xiazaiba.com/html/5861.html

我们要达到的目的是通过md5校验工具将文件的md5值保存到一个log文档中

测试的目录结构

--automd5--

--needCheck--

checkmd5.py

SpyLite24.exe

Hash.exe

needCheck目录放需要检查md5的文件

view source
print ?
001 #! /usr/bin/env python
002 #coding=gbk
003  
004 import time,re,ctypes
005 import os,sys,subprocess,win32gui,win32con,win32api
006 import glob,time
007  
008 #启进程函数
009 def createProcess(cmd, wait = False):
010 if wait:
011 proc = tryExcept(subprocess.Popen, cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
012 else:
013 proc = tryExcept(subprocess.Popen, cmd)
014 if isExcept(proc):
015 return
016 if not wait:
017 return proc.pid
018 proc.communicate()
019  
020  
021 def tryExcept(func, *params, **paramMap):
022 try:
023 return func(*params, **paramMap)
024 except Exception, e:
025 return e
026 def isExcept(e, eType = Exception):
027 return isinstance(e, eType)
028  
029  
030 class BaseWindow:
031 @staticmethod
032 def parseClickConfig(clkCfg):
033 if clkCfg == None:
034 return None, None, False, 0
035 if type(clkCfg) == bool:
036 return None, None, clkCfg, 0
037 if type(clkCfg) == int:
038 return None, None, False, clkCfg
039 if len(clkCfg) == 2:
040 if type(clkCfg[0]) == int and type(clkCfg[1]) == int:
041 return clkCfg[0], clkCfg[1], False, 0
042 return None, None, clkCfg[0], clkCfg[1]
043 if len(clkCfg) == 3:
044 if type(clkCfg[2]) == bool:
045 return clkCfg[0], clkCfg[1], clkCfg[2], 0
046 return clkCfg[0], clkCfg[1], False, clkCfg[2]
047 return clkCfg
048  
049  
050 #点击窗口
051 #clkCfg:byDrv|mode|(x,y)|(byDrv,mode)|(x,y,byDrv)|(x,y,mode)|(x,y,byDrv,mode)
052 def clickWindow(hwnd, clkCfg = None):
053 if isRawWindow(hwnd):
054 return
055 topWindow(hwnd)
056 rect = getWindowRect(hwnd)
057 if not rect:
058 return
059 x, y, byDrv, mode = BaseWindow.parseClickConfig(clkCfg)
060 if x == None:
061 x = (rect[0] + rect[2]) / 2
062 elif x < 0:
063 x += rect[2]
064 else:
065 x += rect[0]
066 if y == None:
067 y = (rect[1] + rect[3]) / 2
068 elif y < 0:
069 y += rect[3]
070 else:
071 y += rect[1]
072 clickMouse(x, y, byDrv, mode)
073  
074 #点击鼠标
075 CLICK_MOUSE = 0
076 CLICK_MOUSE_DOUBLE = 1
077 CLICK_MOUSE_RIGHT = 2
078  
079 def clickMouse(x, y, byDrv = False, mode = CLICK_MOUSE):
080 moveMouse(x, y, byDrv)
081 downMsg, upMsg = win32con.MOUSEEVENTF_LEFTDOWN, win32con.MOUSEEVENTF_LEFTUP
082 if mode == CLICK_MOUSE_RIGHT:
083 downMsg, upMsg = win32con.MOUSEEVENTF_RIGHTDOWN, win32con.MOUSEEVENTF_RIGHTUP
084 win32api.mouse_event(downMsg, 0, 0, 0, 0)
085 win32api.mouse_event(upMsg, 0, 0, 0, 0)
086 if mode == CLICK_MOUSE_DOUBLE:
087 win32api.mouse_event(downMsg, 0, 0, 0, 0)
088 win32api.mouse_event(upMsg, 0, 0, 0, 0)
089  
090 #移动鼠标
091 def moveMouse(x, y, byDrv = False):
092 w, h = win32api.GetSystemMetrics(0), win32api.GetSystemMetrics(1)
093 x, y = int(float(x) / w * 65535), int(float(y) / h * 65535)
094 win32api.mouse_event(win32con.MOUSEEVENTF_MOVE | win32con.MOUSEEVENTF_ABSOLUTE, x, y, 0, 0)
095  
096  
097 #获得窗口尺寸
098 def getWindowRect(hwnd):
099 rect = tryExcept(win32gui.GetWindowRect, hwnd)
100 if not isExcept(rect):
101 return rect
102  
103 #置顶窗口
104 def topWindow(hwnd):
105 fgHwnd = win32gui.GetForegroundWindow()
106 if fgHwnd == hwnd:
107 return True
108 rst = tryExcept(win32gui.SetForegroundWindow, hwnd)
109 if not isExcept(rst):
110 return True
111 return getWindowClass(fgHwnd) == 'Progman' and getWindowText(fgHwnd) == 'Program Manager'
112  
113  
114 ##获取窗口文字
115 def getWindowText(hwnd, buf = ctypes.c_buffer(1024)):
116 size = ctypes.sizeof(buf)
117 ctypes.memset(buf, 0, size)
118 tryExcept(win32gui.SendMessageTimeout, hwnd, win32con.WM_GETTEXT, size, buf, win32con.SMTO_ABORTIFHUNG, 10)
119 return buf.value.strip()
120  
121 #获取窗口类名
122 def getWindowClass(hwnd, buf = ctypes.c_buffer(1024)):
123 size = ctypes.sizeof(buf)
124 ctypes.memset(buf, 0, size)
125 ctypes.windll.user32.GetClassNameA(hwnd, ctypes.addressof(buf), size)
126 return buf.value.strip()
127  
128 #查找第一个窗口
129 #title:text,class,ctrlid
130 #parentTitle:None,hwnd,text,class
131 def findWindow(title, parentTitle = None, isRaw = False):
132 hwndList = findWindows(title, parentTitle, isRaw)
133 if hwndList:
134 return hwndList[0]
135 def findRawWindows(title, parentTitle = None):
136 return findWindows(title, parentTitle, True)
137  
138 #判断是否为非正常窗口
139 def isRawWindow(hwnd):
140 return not win32gui.IsWindowVisible(hwnd) or not win32gui.IsWindowEnabled(hwnd) or ctypes.windll.user32.IsHungAppWindow(hwnd)
141  
142 #查找窗口
143 #title:text,class,ctrlid
144 #parentTitle:None,hwnd,text,class
145 def findWindows(title, parentTitle = None, isRaw = False):
146 def __enumWindowHandler__(hwnd, wndList):
147 text = re.split('[\r|\n]+', getWindowText(hwnd))[0].strip()
148 clazz = getWindowClass(hwnd).strip()
149 ctrlId = win32gui.GetDlgCtrlID(hwnd)
150 wndList.append((hwnd, text, clazz, ctrlId))
151 if not parentTitle:
152 parentHwndList = [None]
153 elif type(parentTitle) == int:
154 parentHwndList = [parentTitle]
155 else:
156 parentHwndList = findRawWindows(parentTitle)
157 hwndSet = set()
158 for parentHwnd in parentHwndList:
159 wndList = []
160 #EnumWindows
161 if parentHwnd:
162 tryExcept(win32gui.EnumChildWindows, parentHwnd, __enumWindowHandler__, wndList)
163 else:
164 win32gui.EnumWindows(__enumWindowHandler__, wndList)
165 #FindWindowEx
166 hwnd, foundHwndList = None, []
167 while True:
168 hwnd = tryExcept(win32gui.FindWindowEx, parentHwnd, hwnd, None, None)
169 if not hwnd or isExcept(hwnd) or hwnd in foundHwndList:
170 break
171 __enumWindowHandler__(hwnd, wndList)
172 foundHwndList.append(hwnd)
173 #GetWindow
174 if parentHwnd:
175 hwnd = tryExcept(win32gui.GetWindow, parentHwnd, win32con.GW_CHILD)
176 else:
177 hwnd = tryExcept(win32gui.GetWindow, win32gui.GetDesktopWindow(), win32con.GW_CHILD)
178 while hwnd and not isExcept(hwnd):
179 __enumWindowHandler__(hwnd, wndList)
180 hwnd = tryExcept(win32gui.GetWindow, hwnd, win32con.GW_HWNDNEXT)
181 #Combine
182 for hwnd, text, clazz, ctrlId in set(wndList):
183 if type(title) == int:
184 if ctrlId == title:
185 hwndSet.add(hwnd)
186 elif text == title or re.match('^' + title + '$', text, re.S) or clazz == title or re.match('^' + title + '$', clazz, re.S):
187 hwndSet.add(hwnd)
188 if parentHwnd:
189 hwndSet.update(findRawWindows(title, hwnd))
190 if isRaw:
191 return list(hwndSet)
192 hwndList = []
193 for hwnd in hwndSet:
194 if not isRawWindow(hwnd):
195 hwndList.append(hwnd)
196 return hwndList
197  
198 #设置窗口文字
199 def setWindowText(hwnd, text):
200 rst = tryExcept(win32gui.SendMessageTimeout, hwnd, win32con.WM_SETTEXT, 0, text, win32con.SMTO_ABORTIFHUNG, 10)
201 return not isExcept(rst)
202  
203 #杀掉指定name的进程
204 def killProcessByName(pname, user = None):
205 killProcessByNames([pname], user)
206  
207 def listFile(path, isDeep=True):
208 _list = []
209 if isDeep:
210 try:
211 for root, dirs, files in os.walk(path):
212 for fl in files:
213 _list.append('%s\%s' % (root, fl))
214 except:
215 pass
216 else:
217 for fn in glob.glob( path + os.sep + '*' ):
218 if not os.path.isdir(fn):
219 _list.append('%s' % path + os.sep + fn[fn.rfind('\\')+1:])
220 return _list
221  
222  
223 #杀掉指定name的进程列表
224 def killProcessByNames(pnameList, user = None):
225 cmd = 'taskkill /F /T'
226 if user:
227 cmd += ' /FI "USERNAME eq %s"' % user
228 for pname in pnameList:
229 cmd += ' /IM %s' % pname
230 createProcess(cmd, True)
231  
232 #超时设置
233 def handleTimeout(func, timeout, *params, **paramMap):
234 interval = 0.8
235 if type(timeout) == tuple:
236 timeout, interval = timeout
237 while timeout > 0:
238 t = time.time()
239 rst = func(*params, **paramMap)
240 if rst and not isExcept(rst):
241 break
242 time.sleep(interval)
243 timeout -= time.time() - t
244 return rst
245  
246 #写文件
247 def setFileData(filename, data, mode):
248 f = open(filename, mode)
249 f.write(data)
250 f.close()
251  
252  
253 if __name__ == '__main__':
254 if os.path.isfile('md5.log'):
255 os.system('del md5.log')
256  
257 parentHwnd = r'Hash.*?'
258 #setWindowText(textblack,'123')
259 filedir = os.path.join(os.getcwd(),'needCheck')
260 filelist = listFile(filedir)
261 #os.chdir(filedir)
262  
263 for file in filelist:
264 #启进程
265 createProcess('Hash.exe')
266 #查找浏览按钮
267 browse_button = findWindow(r'浏览.*?',parentHwnd)
268 #点击浏览按钮
269 clickWindow(browse_button)
270 textblack = findWindow(0x47C,'#32770')
271 handleTimeout(setWindowText,10,textblack,file)
272 open_hwnd = findWindow('打开.*?','#32770')
273 #点击打开按钮
274 clickWindow(open_hwnd)
275 #获取文件md5信息
276 #需要内容的行号
277 expect_content_id = [0,4]
278 content_hwnd = findWindow(0x3EA,r'Hash.*?')
279 content_text = handleTimeout(getWindowText,20,content_hwnd)
280 content = content_text.split('\r\n')
281 md5content = [i.split(': ')[1].strip() for ind, i in enumerate(content) if ind in expect_content_id]
282 print md5content
283 filename,md5value = md5content
284 setFileData('md5.log','文件名:'+filename+'\n'+'md5:'+ md5value+'\n\n','a')
285 killProcessByName('Hash.exe')
286 os.system('pause')

你可能感兴趣的:(Python学习)