准备工作
使用工具:pycharm2021.3
使用模块:selenium4.14.0
部分网页检查展示:
如何查看网页检查:打开一个网页->右击“检查”->在打开的检查框中,有一个选项卡“elements/元素”点击,就可以看到这个网页的前端代码
前置代码:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver=webdriver.Chrome()
driver.get(访问地址)
#访问地址
#本地文件_相对路径:file://pages/***.html
#网页地址:https://www.baidu.com/
常见使用
元素的八大定位
find_element(By.ID,"..."):通过标签中的id属性获取定位
driver.find_element(By.ID,"account").send_keys("abc")
find_element(By.NAME,"..."):通过标签中的name属性获取定位
driver.find_element(By.NAME,"account").send_keys("123456")
find_element(By.CLASS_NAME,"..."):通过标签中的class属性获取定位
driver.find_element(By.CLASS_NAME,"form-control").send_keys("classname")
find_element(By.TAG_NAME,"..."):通过标签的标签名获取定位
driver.find_element(By.TAG_NAME,"input").send_keys("tag_name")
find_element(By.LINK_TEXT,"..."):通过a标签的链接全名作为关键字获取定位
driver.find_element(By.LINK_TEXT,"缺少enter按键").click()
find_element(By_PARTIAL_LINK_TEXT,"..."):通过a标签的链接部分名作为关键字获取定位
driver.find_element(By.PARTIAL_LINK_TEXT,"缺少").click()
find_element(By_XPATH,"..."):在“准备工作”图一的input行右击->“复制/copy”->"复制xpath"获取定位
driver.find_element(By.XPATH,'//*[@id="account"]').send_keys("xpath")
find_element(By_CSS_SELECTOR,"..."):在“准备工作”图一的input行右击->“复制/copy”->"复制selector"获取定位
driver.find_element(By.CSS_SELECTOR,"#account").send_keys("selector")
元素的复数定位
find_elements(By_...,"...")
driver.find_elements(By.CLASS_NAME,"form-control")[0].send_keys("nihao")
时间等待
1.显示等待WebDriverWaits()
2.强制等待time.sleep()
3.隐性等待implicity_wait()
#强制等待
time.sleep(3)
#隐性等待
driver.implicitly_wait(30)
鼠标操作
click(on_element=None) ——单击鼠标左键
context_click(on_element=None) ——点击鼠标右键
double_click(on_element=None) ——双击鼠标左键
#双击操作
a=driver.find_element_by_id("loginName")
ActionChains(driver).double_click(a).perform()
#右击操作
ActionChains(driver).context_click(a).perform()
#单击操作
b=driver.find_element_by_class_name("blue-button")
ActionChains(driver).click(b).perform()
键盘操作
全选(Ctrl+A) Keys.CONTROL,'a'
复制(Ctrl+C) Keys.CONTROL,'c'
粘贴(Ctrl+V) Keys.CONTROL,'v'
下键 Keys.ARROW_DOWN
回车键 Keys.ENTER
删除键 Keys.BACK_SPACE
#全选信息
driver.find_element_by_id("phone").send_keys(Keys.CONTROL,'a')
#复制信息
driver.find_element_by_id("phone").send_keys(Keys.CONTROL,'c')
#粘贴信息
a = driver.find_element_by_id("phone")
a.send_keys(Keys.CONTROL,'v')
操作下拉滚动条
方法一:选择整个界面,进行“键盘操作”的下键操作
ActionChains(driver).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ARROW_DOWN)
方法二:使用script操作,0:横坐标,500:纵坐标
driver.execute_script("window.scrollTo(0,500)")
屏幕截图
get_screenshot_as_file(self,filename)
#存储位置为C盘
driver.get_screenshot_as_file(r"C:\Users\...\denglu.png")
#存储位置为D盘
driver.get_screenshot_as_file("d:\denglu.png")
文件上传
driver.find_element(By.ID,"productImage").send_keys(r"C:\Users\...\1.jpg")
driver.find_element(By.ID,"productImage").send_keys("d:\...\1.jpg")
alert弹出框
text:获取对话框文本值。
accept():相当于点击“确认”
dismiss():相当于点击“取消”
send_keys():输入值,只能在prompt对话框中使用
注意:switch_to_alert()方法定位到alert/confirm/prompt对话框。使用text/accept()/dismiss()/send_keys()进行操作
a = driver.switch_to_alert().text
print(a)
driver.switch_to_alert().accept()
页面元素属性删除
#用selenium定位提交bug按钮
login=driver.find_element(By.LINK_TEXT,'登录')
#删除页面元素的targer属性
driver.execute_script("arguments[0].removeAttribute('target')",login)
#点击 删除targer属性后的登录链接
login.click()
窗口切换
#获取第一个窗口的名字
print(driver.current_window_handle)
#获取所有窗口的名字:
print(driver.window_handles)
#获取到第二个窗口的名字:
print(driver.window_handles[1])
#进行窗口切换:
driver.swtich_to.window(......)
#将窗口切换到第二个窗口
driver.switch_to.window(driver.window_handles[1])
python方法
形式:def 方法名(参数):
def abc():
...
...
abc()
csv文件上传
方式:有两种上传方式:普通、with
csv文件:
import csv
csv_file = open("../data/abc.csv",'r')
csv_obj = csv.reader(csv_file)
for row in csv_obj:
print(row)
import csv
with open("../data/abc.csv",'r') as csv_file:
csv_obj = csv.reader(csv_file)
for row in csv_obj:
print(row)
当运行完上面的代码之后会发现,表头的“测试数据”和“预测数据对比”也显示出来了
解决:还有很多解决方法目前就分享很简单的一种
import csv
with open("../AutomateTest1/data/gupiao.csv",'r') as csv_file:
csv_obj = csv.reader(csv_file)
list = []
for row in csv_obj:
list.append(row)
list.pop(0)
print(list)
unittest自动化框架
使用模块:unittest
使用:定义一个继承unittest.TestCase的测试用例类。
包含:setUp()方法、tearDown()方法、setUpClass()方法、tearDownClass()方法
- setUp()方法指在每个测试用例方法执行前,都会执行一次;
- tearDown()方法指在每次测试用例方法执行结束,都会执行一次;
- setUpClass()方法指在一个测试用例集执行前只执行一次;
- tearDownClass()方法指在一个测试用例集执行后只执行一次。
文件:UnittestCS/cs1.py
import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
class demo01(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Chrome()
def tearDown(self) -> None:
time.sleep(2)
self.driver.quit()
def test_01(self):
self.driver.get("https://www.baidu.com/")
self.driver.find_element(By.ID,"kw").send_keys("苹果")
self.driver.find_element(By.ID,"su").click()
def test_02(self):
self.driver.get("https://www.baidu.com/")
self.driver.find_element(By.ID, "kw").send_keys("榴莲")
self.driver.find_element(By.ID, "su").click()
def test_03(self):
self.driver.get("https://www.baidu.com/")
self.driver.find_element(By.ID, "kw").send_keys("椰子")
self.driver.find_element(By.ID, "su").click()
文件:UnittestCS/cs2.py
import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
class demo02(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.driver = webdriver.Chrome()
@classmethod
def tearDownClass(cls) -> None:
cls.driver.quit()
def test_01(self):
self.driver.get("https://www.baidu.com/")
self.driver.find_element(By.ID,"kw").send_keys("香蕉")
self.driver.find_element(By.ID, "su").click()
time.sleep(2)
def test_02(self):
self.driver.get("https://www.baidu.com/")
self.driver.find_element(By.ID, "kw").send_keys("龙眼")
self.driver.find_element(By.ID, "su").click()
time.sleep(2)
addTest方法
问题:当我只想让一部分测试用例进行测试的时候
解决:使用addTest方法,可以添加部分测试用例进行测试
使用格式:addTest(测试类名(测试方法名))
文件:UnittestCS/AddTestRun.py
import unittest
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from cs1 import demo01
from cs2 import demo02
class demo03(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Chrome()
def tearDown(self) -> None:
time.sleep(2)
self.driver.quit()
def test_01(self):
self.driver.get("https://www.baidu.com/")
self.driver.find_element(By.ID,"kw").send_keys("橘子")
self.driver.find_element(By.ID,"su").click()
if __name__ == "__main__":
# 创建数据集/套件
test_suite = unittest.TestSuite()
# addTest(测试类名(测试方法名))
# 本文件
test_suite.addTest(demo03("test_01"))
# 跨文件
test_suite.addTest(demo01("test_01"))
test_suite.addTest(demo01("test_02"))
test_suite.addTest(demo02("test_01"))
test_suite.addTest(demo02("test_02"))
test_suite.addTest(demo01("test_03"))
# 运行的两种方式
# unittest.TextTestRunner().run(test_suite)
unittest.main(defaultTest="test_suite")
此案例好处:
- 四个之间的使用情况
- 测试用例在本文件内和跨不同文件的使用
- 了解不同的运行方式
discover方法
问题:将所有的测试用例放在一个.py文件中会导致代码变得臃肿,不易修改
解决:使用discover,将测试用例分到多个.py文件中,并进行执行
使用格式:discover(start_dir,pattern='test*.py')
- start_dir:要测试的模块名或测试用例目录
- pattern='test*.py':表示用例文件名的匹配原则。此处匹配文件名以“test*”开头的“.py”类型的文件,星号“”表示任意多个字符
文件:UnittestCS/Discover.py
import unittest
if __name__ == "__main__":
test_dir = "./"
discover = unittest.defaultTestLoader.discover(start_dir=test_dir, pattern="cs*.py")
unittest.TextTestRunner().run(discover)
# unittest.main()
数据断言
介绍
- 数据断言就是用来判断实际结果与预期结果是否一致
- python中有自带的断言,想了解到自己可以先去搜搜,目前没有仔细了解
- unittest断言需要在继承TestCase后才能使用断言
常用的断言方法
断言方法 | 断言描述 | 等价表示 |
assertEqual(a,b) | 判断a和b是否相等 | a == b |
assertIn(a,b) | 判断a是b的子集 | a in b |
assertTrue(a) | 判断a是否为真 | |
assertNotIn(a,b) | 判断a不是b的子集 | a not in b |
assertGreater(a,b) | 判断a>b | a > b |
assertGreaterEqual(a,b) | 判断a>=b | a >= b |
assertLess(a,b) | 判断a<b | a < b |
assertLessEqual(a,b) | 判断a<=b | a <= b |
还有很多但没有写上来 |
ddt
介绍:ddt是unittest可使用的第三方库,用来给unittest做数据驱动(进行参数化)的
安装:pip install ddt
使用过程:在ddt中有几组参数,就会将每组参数都执行一遍
import unittest
import ddt
@ddt.ddt()
class abc(unittest.TestCase):
#基本写法
@ddt.data(1,2,3)
def test_01(self,value):
# 不同的数据输出方式
print(value)
print("abc",value,"cba")
print("test_01,%s"%(f"{value}"))
# 元组和列表的写法
@ddt.data((1,2,3),[4,5,9])
@ddt.unpack
def test_02(self,v1,v2,v3):
print("%s+%s?=%s"%(f"{v1}",f"{v2}",f"{v3}"))
self.assertEqual(int(f"{v1}")+int(f"{v2}"),int(f"{v3}"))
self.assertEqual(int(v1)+int(v2),int(v3))
@ddt.data((1,2,3),[4,5,9])
def test_03(self,v1):
print("%s+%s?=%s"%(f"{v1[0]}",f"{v1[1]}",f"{v1[2]}"))
self.assertEqual(int(f"{v1[0]}")+int(f"{v1[1]}"),int(f"{v1[2]}"))
self.assertEqual(int(v1[0])+int(v1[1]),int(v1[2]))
# 字典写法(形参与键的名字保持一致)
@ddt.data({'un':'abc','pw':'123'},{'un':'def','pw':'123'})
@ddt.unpack
def test_04(self,un,pw):
print("用户名:%s,密码:%s"%(f"{un}",f"{pw}"))
if __name__ == '__main__':
unittest.main(verbosity=2)
合并使用
待更新。。。
补充点
更多ActionChains方法列表
click(on_element=None) | 单击鼠标左键 |
click_and_hold(on_element=None) | 点击鼠标左键,不松开 |
context_click(on_element=None) | 点击鼠标右键 |
double_click(on_element=None) | 双击鼠标左键 |
drag_and_drop(source, target) | 拖拽到某个元素然后松开 |
drag_and_drop_by_offset(source, xoffset, yoffset) | 拖拽到某 个坐标然后松开 |
key_down(value, element=None) | 按下某个键盘上的键 |
key_up(value, element=None) | 松开某个键 |
move_by_offset(xoffset, yoffset) | 鼠标从当前位置移动到某个坐标 |
move_to_element(to_element) | 鼠标移动到某个元素 |
move_to_element_with_offset(to_element, xoffset, yoffset) | 移动到距某个元素(左上角坐标)多少距离的位置 |
perform() | 执行链中的所有动作 |
release(on_element=None) | 在某个元素位置松开鼠标左键 |
send_keys(*keys_to_send) | 发送某个键到当前焦点的元素 |
send_keys_to_element(element, *keys_to_send) | 发送某个键到 指定元素 |
更多Keys方法列表
删除键 | Keys.BACK_SPACE回车键 Keys.ENTER |
空格键 | Keys.SPACE |
TAB键 | Keys.TAB |
回退键 | Keys.ESCAPE |
刷新键 | Keys.F5 |
Shift键 | Keys.SHIFT |
ECS键 | Keys.ESCAPE |
上键 | Keys.ARROW_UP |
下键 | Keys.ARROW_DOWN |
左键 | Keys.ARROW_LEFT |
右键 | Keys.ARROW_RIGHT |
'='键 | EQUALS |
全选(Ctrl+A) | Keys.CONTROL,'a' |
复制(Ctrl+C) | Keys.CONTROL,'c' |
剪切(Ctrl+X) | Keys.CONTROL,'x' |
粘贴(Ctrl+V) | Keys.CONTROL,'v' |