selenium学习笔记

出于了解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实现这两个基础动作

  • 定位,通过HTML中标签元素实现,find_element_by_:

    • name
    • css_selector
    • xpath
    • id
    • link_text/partial_link_text
    • tag_name
    • class_name
    • 以上内容的selectors形式(如果有页面有多个被查找内容,如多个classname=q的情况,使用selectors返回一个list,否则报错:NoSuchElementException
    • 定位函数的官方文档
  • 传值,定位后向目标标签对象传值,使用send_keys()函数

    • send_keys(“text”),一般用于对文本框传值
    • send_keys(Keys.BUTTON_NAME),传特殊键,比如RETURN、F1、左键右键之类的

特殊键合集

单元测试

通过以上内容就可以对页面进行基本的操作了,但是要进行真正的单元测试,需要搭配正经的单元测试框架使用:

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):
#实例化driver=chrome的webdriver

def test_search_in_python_org(self):
main_page=page_obj.MainPage(self.driver)#实例化一个MainPage,

#检查标题是否包含’python‘
assert main_page.is_title_matches(),"python.org title doesn't match."
#将pycon传入搜索框
main_page.search_text_element="pycon"
#点击submit按钮
main_page.click_go_button()
#有内容返回True,没有则返回False
search_results_page=Page_obj.SearchResultPage(self.driver)
assert search_results_page.is_result_fount(),"No result found"

def tearDown(self):
#driver关了

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’}

#设置cookie的方法
driver.add_cookie(cookie)
#取得cookies的方法
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()#用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得到它位于图片的方位(左上角那个点)
location = element.location
#得到size
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']
#用PIL.Image.crop截图
im = im.crop((left, top, right, bottom))
im.save('screenshot.png') # 存新图

一些感受

selenium比较基础和重要的就是定点和传值,实际上所有关于测试的内容也都是这个基础上的衍生,感觉是一个比较友好的库,函数什么的写得很清晰,实际操作的时候如果碰到问题去Doc上找找也能解决。