form 表单是常用的测试用例对象,大多数 web 应用程序都有这方面的功能。例如:用户登录、注册都会用到 form 表单。
form 表单的流程:
定位表单元素
输入测试值
判断表单元素属性
获取表单元素属性
提交表单进行验证
实例:在本地使用了 file 协议加载本地文件,自定义一个 form 表单,使用 selenium 实现了表单的数据输入、提交。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <form action ="javascript:alert('hello')" > username: <input type ="text" name ="username" id ="username" > <br > password: <input type ="password" name ="password" id ="password" > <br > submit<input type ="submit" value ="submit" id ="submit" > </form > </body > </html >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import osfrom time import sleepfrom selenium import webdriverfrom Selenium.utils.util import PROJECT_PATH class TestCase (object ): def __init__ (self ): self .path = os.path.join(PROJECT_PATH, 'static' ) self .forms_file = 'file:///' + self .path + '/demo2_3_forms.html' self .driver = webdriver.Chrome() def quit (self ): self .driver.quit() def get_forms_file (self ): self .driver.get(self .forms_file) def test_login (self ): self .get_forms_file() username = self .driver.find_element_by_id('username' ) username.send_keys('admin' ) password = self .driver.find_element_by_id('password' ) password.send_keys('123456' ) print (username.get_attribute('value' )) print (password.get_attribute('value' )) sleep(2 ) self .driver.find_element_by_id('submit' ).click() sleep(1 ) self .driver.switch_to.alert.accept() sleep(1 ) username.clear() password.clear() sleep(1 ) self .quit() if __name__ == '__main__' : case = TestCase() case .test_login()
form 表单里常用 checkbox 和 radiobutton, checkbox 是多选框,radiobutton 是单选框;
例如,一个注册表单收集用户爱好可以用 checkbox,输入性别可以用 radiobutton;
关于 checkbox
如果 checkbox 有 id 属性,可以直接通过 id 定位;若没有则通过 input 标签名称定位,然后通过 type 属性过滤;
选择或反选 checkbox,使用 click() 方法;
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <form action ="javascript:alert('test')" > swimming: <input type ="checkbox" name ="swimming" value ="swimming" > <br > reading: <input type ="checkbox" name ="reading" value ="reading" > <br > <hr > gender: <input type ="radio" name ="gender" value ="male" > male   <input type ="radio" name ="gender" value ="female" > female <br > login: <input type ="submit" name ="submit" > </form > </body > </html >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import osfrom time import sleepfrom selenium import webdriverfrom Selenium.utils.util import PROJECT_PATHclass TestCase (object ): def __init__ (self ): self .path = os.path.join(PROJECT_PATH, 'static' ) self .file = 'file:///' + self .path + '/demo2_4_checkbox_radiobutton.html' self .driver = webdriver.Chrome() def get_path (self ): self .driver.get(self .file) def quit (self ): self .driver.quit() def test_checkbox (self ): self .get_path() sleep(2 ) checkbox1 = self .driver.find_element_by_name('swimming' ) checkbox2 = self .driver.find_element_by_name('reading' ) for ele in [checkbox1, checkbox2]: if not ele.is_selected(): ele.click() sleep(1 ) self .quit() def test_radiobutton (self ): self .get_path() radios = self .driver.find_elements_by_name('gender' ) for radio in radios: radio.click() sleep(1 ) self .quit() if __name__ == '__main__' : case = TestCase() case .test_radiobutton()
Selenium 操作下拉列表 处理下拉列表,需要用到工具栏 Select 。
#
方法/属性
方法/属性描述
1
select_by_value()
根据值选择
2
select_by_index()
根据索引选择
3
select_by_visible_text()
根据文本选择
4
deselect_by_value
根据值反选
5
deselect_by_index
根据索引反选
6
deselect_by_visible_text
根据文本反选
7
deselect_all
反选所有
8
options
所有选项
9
all_selected_options
所有选中选项
10
first_selected_option
第一个选择选项
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <form action ="javascript:alert('test select')" > <label for ="provise" > provide:</label > <select name ="provise" id ="provise" multiple > <option value ="bj" > beijing</option > <option value ="hz" > hangzhou</option > <option value ="nj" > nanjing</option > </select > </form > </body > </html >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 import osfrom time import sleepfrom selenium import webdriverfrom selenium.webdriver.support.select import Selectfrom Selenium.utils.util import PROJECT_PATHclass TestCase (object ): def __init__ (self ): self .path = os.path.join(PROJECT_PATH, 'static' ) self .file = 'file:///' + self .path + '/demo2_5_select.html' self .driver = webdriver.Chrome() def get_path (self ): self .driver.get(self .file) sleep(2 ) def quit (self ): self .driver.quit() def test_select_by_value (self ): ele = self .driver.find_element_by_id('provise' ) select_obj = Select(ele) select_obj.select_by_value('nj' ) sleep(1.5 ) select_obj.select_by_value('hz' ) sleep(1.5 ) def test_select_by_index (self ): ele = self .driver.find_element_by_id('provise' ) select_obj = Select(ele) select_obj.select_by_index(2 ) sleep(1.5 ) select_obj.select_by_index(1 ) sleep(1.5 ) select_obj.select_by_index(0 ) sleep(1.5 ) def test_select_by_visible_text (self ): ele = self .driver.find_element_by_id('provise' ) select_obj = Select(ele) select_obj.select_by_visible_text('beijing' ) sleep(1.5 ) select_obj.select_by_visible_text('nanjing' ) sleep(1.5 ) def test_select_multiple (self ): ele = self .driver.find_element_by_id('provise' ) select_obj = Select(ele) for i in range (3 ): select_obj.select_by_index(i) sleep(1 ) select_obj.deselect_all() sleep(1 ) def test_options (self ): ele = self .driver.find_element_by_id('provise' ) select_obj = Select(ele) for option in select_obj.options: print (option) print (option.text) if __name__ == '__main__' : case = TestCase() case .get_path() case .test_options() case .quit()
Selenium 处理弹框 页面上的弹框有三种:
alert:用来提示
confirm:用来确认
prompt:输入内容
#
方法/属性
方法/属性描述
1
accept()
接受
2
dismiss()
取消
3
text
显示的文本
4
send_keys
输入内容
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <a href ="javascript:alert('提示框')" id ="alert" > <br > Alert </a > <a href ="javascript:confirm('确认框')" id ="confirm" > <br > Confirm </a > <a href ="javascript:var inputvar = prompt('请输入');document.write(inputvar)" id ="prompt" > <br > Prompt </a > </body > </html >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 import osfrom selenium import webdriverfrom time import sleepfrom Selenium.utils.util import PROJECT_PATHclass TestCase (object ): def __init__ (self ): self .path = os.path.join(PROJECT_PATH, 'static' ) self .file = 'file:///' + self .path + '/demo2_6_alert.html' self .driver = webdriver.Chrome() def get_path (self ): self .driver.get(self .file) sleep(2 ) def quit (self ): self .driver.quit() def test_alert (self ): self .get_path() ele = self .driver.find_element_by_id('alert' ) ele.click() alert_obj = self .driver.switch_to.alert print (alert_obj.text) sleep(1 ) alert_obj.accept() sleep(1 ) self .quit() def test_confirm (self ): self .get_path() for i in range (2 ): ele = self .driver.find_element_by_id('confirm' ) ele.click() alert_obj = self .driver.switch_to.alert sleep(1 ) if i == 0 : alert_obj.accept() else : alert_obj.dismiss() sleep(1 ) self .quit() def test_prompt (self ): self .get_path() ele = self .driver.find_element_by_id('prompt' ) ele.click() prompt_obj = self .driver.switch_to.alert print (prompt_obj.text) sleep(3 ) prompt_obj.accept() sleep(3 ) self .quit() if __name__ == '__main__' : case = TestCase() case .test_prompt()
Selenium 三种等待方式 在 UI 自动化测试中,必然会遇到测试环境不稳定的情况,网络延迟等,如果不做任何处理,代码会由于没有找到元素而报错。除此,有的页面会使用 ajax 异步加载机制,需要用到等待。
常用的等待有三种:
time.sleep 固定等待
在开发自动化测试框架过程中,忌讳使用Python自带模块time的sleep方法进行等待,虽然可以自定义时间,当时当网络条件好时,依旧会等待,导致整个项目的测试时间没有必要的延长。只是在脚本调试是推荐使用。
implicitly_wait 隐式等待
设置了一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直会等待时间结束,然后执行下一步。这样的隐式等待会有问题,页面上的元素加载完毕后再加载 body 后面的 JavaScript,导致一直在等待页面加载结束。
隐式等待对整个 driver 周期都起作用,在最开始设置一次就可以。不要当做笃定等待使用、到哪都使用。
WebDriverWait 显式等待
WebDriverWait 是 selenium 提供得到显示等待的模块,引入路径:
1 from selenium.webdriver.support.wait import WebDriverWait
WebDriverWait 参数:
#
参数
参数说明
1
driver
传入 WebDriver 实例
2
timeout
超时时间,等待的最长时间
3
poll_frequency
调用until或until_not中的方法的间隔时间,默认是0.5秒
4
ignored_exceptions
忽略的异常
该模块中一共只要两种方法:until 和 until_not
#
参数
参数说明
1
method
在等待时间,每隔一段时间调用这个传入的方法,直到返回值不是False
2
message
如果超时,抛出TimeoutException异常,将message传入异常
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class TestCase (object ): def __init__ (self ): self .driver = webdriver.Chrome() self .driver.get('https://www.baidu.com' ) def test_sleep (self ): self .driver.find_element_by_id('kw' ).send_keys('selenium' ) sleep(3 ) self .driver.find_element_by_id('su' ).click() sleep(3 ) self .driver.quit() def test_implicitly (self ): self .driver.implicitly_wait(10 ) self .driver.find_element_by_id('kw' ).send_keys('selenium' ) self .driver.find_element_by_id('su' ).click() self .driver.quit() def test_wait (self ): wait = WebDriverWait(self .driver, 5 , 0.5 ) wait.until(EC.title_is('百度一下,你就知道' )) self .driver.find_element_by_id('kw' ).send_keys('selenium' ) self .driver.find_element_by_id('su' ).click() self .driver.quit() if __name__ == '__main__' : case = TestCase() case .test_wait()
Selenium 等待条件
#
条件
判断
返回值
1
title_is
title,是否出现
布尔
2
title_contains
title,是否包含某些子字符串
布尔
3
presence_of_element_located
某个元素是否被在dom树里,并不代表该元素一定可见
WebElement
4
url_contains
当前url中包含子字符串
布尔
5
url_matches
当前url匹配某表达式
布尔
6
url_to_be
url是否相同
布尔
7
url_changes
url不能准确匹配
布尔
8
visibility_of_element_located
某个元素是否被在dom里并且可见,宽和高都大于0
WebElement
9
visibility_of
元素是否可见,若可见就返回这个元素
WebElement
10
presence_of_all_elements_located
是否至少有1个元素存在dom树中
列表
11
visibility_of_any_elements_located
至少有1个元素在页面中可见
列表
12
text_to_be_present_in_element
指定元素中是否包含了预期的文本
布尔
13
text_to_be_present_in_element_value
指定元素的属性值中是否包含了预期的文本
布尔
14
frame_to_be_available_and_switch_to_it
该frame是否可以switch进去,若是则切进去
布尔
15
invisibility_of_element_located
某个元素是否存在于dom或不可见
布尔
16
element_to_be_clickable
某个元素是否可见并且是enabled的,代表可点击
布尔
17
staleness_of
等待某个元素从dom树中移除
布尔
18
element_to_be_selected
某个元素是否被选中了,一般用在下拉列表
布尔
19
element_located_to_be_selected
某个定位元素是否被选中了
布尔
20
element_selection_state_to_be
某个元素的选中状态是否符合预期
布尔
21
element_located_selection_state_to_be
某个元素的选中状态是否符合预期
布尔
22
alert_is_present
页面上是否存在alert
alert
Selenium 鼠标和键盘操作 Selenium 中的鼠标和键盘时间被封装在 ActionChains 类中,正确的使用方法是:ActionChains(driver).click(btn).perform() ,下面是常用方法。
#
方法
描述
1
perform
执行链中的所有动作
2
reset_actions
清空链中已经存储的所有动作
3
click
点击一个元素
4
click_and_hold
在一个元素上单击并保持
5
context_click
在一个元素上右击
6
double_click
双击一个元素
7
drag_and_drop
在一个元素上单击并拖动到另一个元素上再释放(拖拽)
8
drag_and_drop_by_offset
在一个元素上单击并拖动固定距离到另一个坐标点
9
key_down
键盘上按下某个键
10
key_up
键盘上释放某个键
11
move_by_offset
鼠标从当前位置移动到某个坐标
12
move_to_element
鼠标移动到某个元素
13
move_to_element_with_offset
移动到距某个元素(左上角坐标)多少距离的位置
14
pause
在一定时间内,暂停所有的输入
15
release
在一个元素上释放鼠标左键
16
send_keys
发送数据到当前焦点的元素
17
send_keys_to_element
发送某个键到指定元素
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 from time import sleepfrom selenium import webdriverfrom selenium.webdriver import ActionChainsfrom selenium.webdriver.common.keys import Keysclass TestCase (object ): def __init__ (self ): self .driver = webdriver.Chrome() self .driver.maximize_window() def test_mouse (self ): self .driver.get('http://sahitest.com/demo/clicks.htm' ) doubleclick_ele = self .driver.find_element_by_xpath('/html/body/form/input[2]' ) ActionChains(self .driver).double_click(doubleclick_ele).perform() click_ele = self .driver.find_element_by_xpath('/html/body/form/input[3]' ) ActionChains(self .driver).click(click_ele).perform() rightclick_ele = self .driver.find_element_by_xpath('/html/body/form/input[4]' ) ActionChains(self .driver).context_click(rightclick_ele).perform() def test_mouse_reset (self ): self .driver.get('http://sahitest.com/demo/clicks.htm' ) actionchains = ActionChains(self .driver) doubleclick_ele = self .driver.find_element_by_xpath('/html/body/form/input[2]' ) actionchains.double_click(doubleclick_ele).perform() actionchains.reset_actions() click_ele = self .driver.find_element_by_xpath('/html/body/form/input[3]' ) actionchains.click(click_ele).perform() actionchains.reset_actions() rightclick_ele = self .driver.find_element_by_xpath('/html/body/form/input[4]' ) actionchains.context_click(rightclick_ele).perform() def test_keys (self ): self .driver.get('http://www.baidu.com' ) kw_ele = self .driver.find_element_by_id('kw' ) kw_ele.send_keys('selenium' ) kw_ele.send_keys(Keys.CONTROL, 'a' ) sleep(1 ) kw_ele.send_keys(Keys.CONTROL, 'x' ) sleep(1 ) kw_ele.send_keys(Keys.CONTROL, 'v' ) config_ele = self .driver.find_element_by_name('tj_settingicon' ) ActionChains(self .driver).move_to_element(config_ele).perform() forcast_ele = self .driver.find_element_by_link_text('关闭预测' ) ActionChains(self .driver).click(forcast_ele).perform() if __name__ == '__main__' : case = TestCase() case .test_keys()
Selenium 执行 JavaScript 脚本 WebDriver 有两个方法来执行 JavaScript,分别是:
execute_script 同步执行
execute_async_script 异步执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 from time import sleepfrom selenium import webdriverclass TestCase (object ): def __init__ (self ): self .driver = webdriver.Chrome() self .driver.get("http://www.baidu.com" ) self .driver.maximize_window() def test_js1 (self ): self .driver.execute_script('alert("test_javascript")' ) sleep(1 ) self .driver.switch_to.alert.accept() def test_js2 (self ): js_sentence = 'return document.title' title = self .driver.execute_script(js_sentence) return title def test_js3 (self ): js_sentencce = "var q = document.getElementById('kw'); q.style.border='2px solid red'" self .driver.execute_script(js_sentencce) def test_js4 (self ): self .driver.implicitly_wait(5 ) self .driver.find_element_by_id('kw' ).send_keys('python' ) self .driver.find_element_by_id('su' ).click() sleep(1 ) js_sentence = "window.scrollTo(0, document.body.scrollHeight)" self .driver.execute_script(js_sentence) if __name__ == '__main__' : case = TestCase() case .test_js4()
Selenium 屏幕截图 WebDriver 内置了一些在测试中捕获并保存的方法:
#
方法
描述
1
save_screenshot(filename)
获取当前屏幕截图并保存为文件,filename为指定保存的路径或图片的文件名
2
get_screenshot_as_base64()
获取当前屏幕截图base64编码字符串
3
get_screenshot_as_file(filename)
获取当前的屏幕截图,使用完整的路径
4
get_screenshot_as_png()
获取当前屏幕截图的二进制文件数据
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import osfrom time import sleep, strftime, localtime, timefrom selenium import webdriverfrom utils.util import PROJECT_PATHclass TestCase (object ): def __init__ (self ): self .path = PROJECT_PATH self .driver = webdriver.Chrome() self .driver.get("http://www.baidu.com" ) self .driver.maximize_window() def test1 (self ): self .driver.find_element_by_id('kw' ).send_keys('截屏' ) self .driver.find_element_by_id('su' ).click() sleep(1 ) str_time = strftime("%Y-%m-%d-%H-%M-%S" , localtime(time())) screenshot_dir = os.path.join(self .path, 'screenshot' ) if not os.path.exists(screenshot_dir): os.mkdir(screenshot_dir) file_name = os.path.join(screenshot_dir, str_time + '.png' ) self .driver.save_screenshot(file_name) if __name__ == '__main__' : case = TestCase() case .test1()
Selenium 定位 frame iframe frame 标签有 frameset、frame、iframe 三种,frameset 跟其他普通标签没有区别,不会影响到正常的定位,而 frame 与 iframe 对 Selenium 定位而言是一样的,Selenium 有一组方法对 frame 进行操作。
#
方法
描述
1
switch_to.frame(reference)
切换frame,reference是传入的参数,用来定位frame,可以传入id,name,index以及selenium的WebElement对象
2
switch_to.default_content()
返回主文档
3
switch_to.parent_frame()
返回父文档
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 from time import sleepfrom selenium import webdriverclass TestCase (object ): def __init__ (self ): self .driver = webdriver.Chrome() self .driver.get("http://sahitest.com/demo/framesTest.htm" ) def test_frame (self ): self .driver.implicitly_wait(10 ) frame1_ele = self .driver.find_element_by_name('top' ) self .driver.switch_to.frame(frame1_ele) Link_Test = self .driver.find_element_by_xpath("/html/body/table/tbody/tr/td[1]/a[1]" ) Link_Test.click() self .driver.switch_to.default_content() sleep(3 ) frame2_ele = self .driver.find_element_by_xpath("/html/frameset/frame[2]" ) self .driver.switch_to.frame(frame2_ele) Link_Test2 = self .driver.find_element_by_xpath("/html/body/table/tbody/tr/td[1]/a[1]" ) Link_Test2.click() if __name__ == '__main__' : case = TestCase() case .test_frame()