文件上传是做UI自动化测试时候的一个大问题,尝试了一下网上各种上传文件的方式,以下试验按照使用频率来排名。(多个方法多个思路,你要不想学“茴”字的四种写法,看第一个就够了)
在动手之前,我们要区分出上传按钮的种类,大体上可以分为两种
- 一种是input框
- 另外一种就比较复杂,通过js、flash等实现,标签非input
我们分别对这两种进行分析:
1.input标签
众所周知,input标签是可以直接send_keys的,这种情况下就简单粗暴,来看代码示例:
1 from selenium import webdriver
2 import time
3
4 driver = webdriver.Firefox()
5 driver.get('url')
6 driver.find_element_by_name('myfile').send_keys('d:\\test.png') #输入的是文件的绝对路径。
2.非input型上传
那么对于那些不是input框实现的上传怎么办,这种上传千奇百怪,有用a标签的,有用div的,有用button的,有用object的,我们没有办法通过直接在网页上处理掉这些上传,唯一的办法就是打开windows的系统弹框,去处理弹框。
问题又来了,Selenium2.0还不能解决掉windows系统弹框的问题,怎么办?很简单,用OS层面的操作去处理呗(谁家的孩子谁家领回家的思维方式在哪里都好用)
大体上有以下四种解决方案:
• Python pywin32库,识别对话框句柄,进而操作
• pywinauto库
• pyautogui库
• autoIT,借助外力,我们去调用其生成的au3或exe文件。
NO 1:pywin32库
1 首先安装pywin32库(命令:pip install pywin32)
2 代码示例
from selenium import webdriver
import win32gui
import win32con
dr = webdriver.Firefox()
dr.get('http://localhost/test/fileupload.html')
dr.find_element_by_id('file').click()# win32gui
dialog = win32gui.FindWindow('#32770', '文件上传') # 对话框
ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None) # 上面三句依次寻找对象,直到找到输入框Edit对象的句柄
button = win32gui.FindWindowEx(dialog, 0, 'Button', None) # 确定按钮Button
win32gui.SendMessage(Edit, win32con.WM_SETTEXT, None, 'd:\\all_money.wmv') # 往输入框输入绝对地址
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button) # 按button
这个地方大家其实对识别对话框的句柄有问题,这个在使用autoIt的时候可以解决掉,或者使用Spy++这个小工具。其它的也就是win32gui里面的api调用方式。
NO 2:AutoIt
1 pip install pywinauto
代码如下:
1 from selenium import webdriver
2 from pywinauto import Desktop
3 import time
4 dr=webdriver.Chrome()
5
6 dr.get('url')
7 dr.maximize_window()
8 time.sleep(1)
9
10 # 操作系统的指令
11 wd = Desktop()
12 open = wd['打开'] #根据名字找到弹出窗口
13 open["Edit"].type_keys("D:\demo.txt") # 在输入框中输入值
14 open["Button"].click()
NO 3:pyautogui库
from selenium import webdriver
import pyautogui
import time
dr=webdriver.Chrome()
dr.get('url')
dr.maximize_window()
dr.find_element_by_name('myfile').click()
time.sleep(1)
pyautogui.write(r'd:\demo.txt')
time.sleep(1)
pyautogui.press('enter')#回车按键
但是路径内有中文的话这种方法是不支持的,解决方法如下:
from selenium import webdriver
import pyautogui
import pyperclip
import time
dr=webdriver.Chrome()
dr.get('url')
dr.maximize_window()
dr.find_element_by_name('myfile').click()
pyperclip.copy(r'd:\测试.txt')
time.sleep(1)
pyautogui.hotkey('ctrl','v')
time.sleep(1)
pyautogui.press('enter')
time.sleep(2)
NO 4:AutoIt
对于OS弹框,上传、下载等,均可以用 autoit 进行处理,同时还可以通过传参对要传的文件进行参数化:
想要参数化传入的参数,可以通过autoit的命令行参数:
D:\ uploadfile.exe param1 "This is an int parameter" 102
在脚本中,可用以下变量获取命令行参数:
$CmdLine[0] ; = 3
$CmdLine[1] ; = param1
$CmdLine[2] ; = "This is an int parameter"
$CmdLine[3] ; = 102
$CmdLineRaw ; = 'param1 "This is a string parameter" 99'
$CmdLine[0] 获取的是命令行参数的总数,在上例中参数有3个。
$CmdLine[1]~$CmdLine[63] 获取的是命令行参数第1到第63位,这个方式最多只能获取63个参数,不过正常情况下是足够用的
$CmdLineRaw 获取的是未拆分的所有参数,是一个长字符串,这种情况下不局限与63个参数
通过autoit的获取对象并编辑脚本:
ControlFocus("文件上传", "", "Edit1")
WinWait("[CLASS:#32770]", "", 10)
ControlSetText("文件上传" ,"", "Edit1", $CmdLine[1])
Sleep(2000)
ControlClick("文件上传", "","Button1");
通过Aut2Exe工具将脚本转成exe文件(uploadfile.exe)
接着就可以使用Python中的os模块来运行这个exe执行程序了。
# -*- coding: utf-8 -*-
from selenium import webdriver
import os
import time
driver = webdriver.Firefox()
driver.get('http://localhost/test/fileupload.html')
driver.find_element_by_id('file').click()
time.sleep(1)
os.system('D:\\Python\\Demo\\uploadfile.exe "d:\\all_money.wmv" ') # 这里可以对传参进行参数化,我们可以通过py脚本来控制所要上传的文件了
time.sleep(3)
driver.quit()
注意点:关于OS弹框的title,不同浏览器是不一样的,一般firefox是“文件上传”、chrome叫“打开”、而IE则叫“选择要加载的文件”,对于这个问题,你可以写三个不同脚本,
在处理弹框的方法中根据浏览器类型的不同而进行选择,或者每次去获取所有类型弹框,再或者通过参数传入该弹框的名称。
进阶版:
刚才的几种方法都是上传单个的文件的操作,如果我想上传多个文件怎么办呢?
答案很简单:
多文件上传就是在文件路径框里用引号括起单个路径,然后用空格隔开多个路径,例如:
“D:\allmoney.txt” “D:\allgirls.txt”
注意点为:所有文件最好放于同一路径下,才能这样用,否则是会失败的。(这个还没找到合适的网站测试,稍后添加)