出于了解Web自动化测试的意图学习了selenium。
selenium不完全是个python库,除了python,图像化界面、Java代码也可以操控它。
通过selenium编写代码可以实现人类操作web的行为。
1 2 3 4
| from selenium import webdriver
driver = webdriver.Chrome('chromedriver_path') driver.get("https://www.google.com")
|
上面的代码将操纵chrome浏览器的webdriver,自动打开Chrome浏览器,连接google主页。selenium的webdriver库只提供API,实际的操作还是要通过浏览器的驱动实现。chrome的驱动器叫ChromeDriver,直接搜索就能下载。不过要注意不同版本的ChromeDriver适配不同的Chrome版本,如果版本不匹配在实际操作中会出现闪退的情况。
基操
实现测试的时候需要以下比较得体的抓取和传值,selenium通过下面的api实现这两个基础动作
特殊键合集
单元测试
通过以上内容就可以对页面进行基本的操作了,但是要进行真正的单元测试,需要搭配正经的单元测试框架使用:
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
| import unittest from selenium import webdriver from selenium.webdriver.common.keys import Keys
class PythonOrgSearch(unittest.TestCase): ''' #setUp 和 tearDown 都是unittest自己具备的。 在所有测试函数开始前启动setUp,所有测试结束后启动tearDown ''' def setUp(self): self.driver = webdriver.Chrome() def test_search_in_python_org(self): ''' 获得python主页的页面->页面<title>中包括“Python” -> 定位到name=q的标签(是个搜索框) -> 清除搜索框中的预输入,传入自己想用的内容,按回车 -> 能查找到内容 ''' driver = self.driver driver.get("http://www.python.org") self.assertIn("Python", driver.title) elem = driver.find_element_by_name("q") elem.clear() elem.send_keys("pycon") elem.send_keys(Keys.RETURN) assert "No results found" not in driver.page_source
def tearDown(self): self.driver.close()
if __name__ == "__main__": unittest.main()
|
规矩一点的测试
以上的内容就已经通过selenium+unittest组合成了一个单元测试模块,不过还不算“page objects design pattern”。根据官网的内容,一个”page objects”需要做到:
- 可复用
- 节省代码量
- 当用户接口改变,只需修改一个接口代码
在官网的PageObject中可以看到所有的代码,下面是根据我自己理解写的注释内容:
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
| '''unittest.py''' from selenium import webdriver import unittest
import Page_obj '''Page_obj包括: BasePage: 初始化driver SearchTextElement(BasePageElement): 继承另一个模块Page_element中的BasePageElement类, 该类重写了__set__和__get__, set用于找到子类中需要查找的标签,通过send.keys()传值给标签; get用于返回子类中需要查找的标签的"value"属性 MainPage(BasePage): 1) 实例化SearchTextElement 2) is_title_matches()检查"python"是不是在driver.title中 3) click_go_button()找到MainPageLocators中用户定义的按钮,click()它 SearchResultPage(BasePage) 包含is_resultPage,如果当前页面有内容返回True否则为False ''' class PythonOrgSearch(unittest.TestCase): '''unittest对象,本个测试内容和上一节测试内容是一样的,仅仅是上一节的正规形式而已''' def setUp(self): def test_search_in_python_org(self): main_page=page_obj.MainPage(self.driver) assert main_page.is_title_matches(),"python.org title doesn't match." main_page.search_text_element="pycon" main_page.click_go_button() search_results_page=Page_obj.SearchResultPage(self.driver) assert search_results_page.is_result_fount(),"No result found" def tearDown(self):
|
Page Obj 能实现节省代码量和单次修改,具体的作用如下:
- 如果想传参进其他的空间(而非原文中的搜索框),只用改变
SearchTextElement中的locator
- 如果想点击其他的按钮,改变
MainPageLocators中的按钮就好
- 任何带输入框、可传值、取value属性中内容的东西,都可以用重写过set&get方法的
BasePageElement对象通过’=’&’.’实现,减少代码量
- 所有的函数方法都是可复用的
其他的东西
cookies
有时,一些资源需要携带cookie才能被请求。selenium.webdriver下有关于cookie的函数可用:
1 2 3 4 5 6 7
| driver.get("http://www.example.com") cookie = {‘name’ : ‘foo’, ‘value’ : ‘bar’}
driver.add_cookie(cookie)
driver.get_cookies()
|
需要先get(),确定driver的域名,再add_cookie。get_cookies会得到发送和接收的cookie列表。
Action_Chain
可以一个接一个地完成鼠标操作,做简单的动作的时候可以串起来显得代码好看
1 2 3 4
| menu = driver.find_element_by_css_selector(".nav") hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()
|
截图
截图比较有用,也记了一下
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
| from selenium import webdriver from PIL import Image
driver = webdriver.Chrome() driver.get('https://stackoverflow.com/')
element = driver.find_element_by_id('hlogo')
location = element.location
size = element.size
driver.save_screenshot('screenshot.png') driver.quit()
im = Image.open('screenshot.png')
left = location['x'] top = location['y'] right = location['x'] + size['width'] bottom = location['y'] + size['height']
im = im.crop((left, top, right, bottom)) im.save('screenshot.png')
|
一些感受
selenium比较基础和重要的就是定点和传值,实际上所有关于测试的内容也都是这个基础上的衍生,感觉是一个比较友好的库,函数什么的写得很清晰,实际操作的时候如果碰到问题去Doc上找找也能解决。