一、UI自动化测试基础知识点(元素定位暂不写)
1、 技术架构:python+selenium;
2、 自动化测试webdriver运行原理:
自动化测试代码发送请求给浏览器的驱动,浏览器驱动自动识别代码,解析后发送给浏览器,浏览器执行驱动发来的指令,完成自动化测试的工作;
3、 webdriver长用属性以及方法:
driver.title---查看标题
driver.Current_url----查看地址
driver.windows_handles----查看浏览器句柄
4、 close()与quit()区别:
close---退出当前页面,quit---退出浏览器;
5、 webelement属性以及方法:
属性:
id:标识;
size:宽高;
rect:宽高和坐标;
tag_name:标签名称;
text:文本内容;
方法:
Send_size:输入内容
Click:点击
Clear:清除
Is_selected:是否被选中;
6、 form表单操作:
流程:定位表单元素、输出测试数据、判断表单元素属性、获得表单元素属性、提交表单进行验证;
7、 下拉列表操作:
Select_by_value():根据值选择
Select_by_index():根据索引选择
Select_by_visible_text():根据文本选择
弹窗处理:
1、alert:普通提示框。切换至弹窗--self.driver.swich_to.alert
2、confirm:删除数据提示框。切换至弹窗--self.driver.swich_to.alert
3、prompt:输入文本内容提示框。切换至弹窗--self.driver.swich_to.alert
以上三种弹窗的方法:accept()--接受、dismiss()--取消、text()--显示文本、send_keys()--输入内容;
三种等待:
1、wait:遇到环境网络等不稳定时候,如果不做处理,代码会因为没有找到元素而报错,这个时候需要使用wait等待方式;
2、time.sleep:让当前的线程睡眠,用于调试脚本;
3、implicitly_wait:隐式等待,最开始设置一次全程有效,按规定时间内网页加载完成,才执行下一步,否则会抛出异常;
4、webdriverwait:显式等待;参数:driver--webdriver实例、timeout--设置超时时间、poll_frequency--调试方法中的时间,默认0.5秒。方法:until--等待时间内,每隔一段时间传入这个方法,查看返回结果是不是TRUE、message--如果超时,就传入message异常;
鼠标操作:
之前定位的时候,用到了click点击元素,selenium除了click模拟鼠标单击操作外,还提供了双击、右击、悬停、拖动等操作,使用这些要导入ActionChains类:
from selenium.webdriver.common.action_chains import ActionChains。
ActionChains提供的操作如下:
* perform() 执行所有 ActionChains 中存储的行为
* context_click() 右击
* double_click() 双击
* drag_and_drop() 拖拽到某个元素
* move_to_element() 鼠标悬停
* drag_and_drop_by_offset()拖拽到某个坐标
示例:
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep
driver=webdriver.Chrome()
driver.get("https://www.baidu.com/")
driver.maximize_window()
driver.find_element_by_css_selector("#kw").send_keys("锄禾")
#获取搜索框元素对象
element=driver.find_element_by_css_selector("#kw")
sleep(3)
#双击
ActionChains(driver).double_click(element).perform()
sleep(2)
#右击
ActionChains(driver).context_click(element).perform()
#鼠标悬停
#悬停在设置上
above=driver.find_element_by_css_selector(".pf")
ActionChains(driver).move_to_element(above).perform()
sleep(3)
driver.quit()
键盘操作:
1.模拟键盘的操作需要先导入键盘模块:
from selenium.webdriver.common.keys import Keys
2.Keys()类提供了键盘上几乎所有按键的方法。前面了解到,send_keys()方法可以用来模拟键盘 输入, 除此 之外, 我们还可以用它来输入键盘上的按键甚至是组合键, 如 Ctrl+A、 Ctrl+C 等。
3.常见的键盘操作:
send_keys(Keys.BACK_SPACE) #删除键(BackSpace)
send_keys(Keys.SPACE) #空格键(Space)
send_keys(Keys.TAB) #制表键(Tab)
send_keys(Keys.ESCAPE) #回退键(Esc)
send_keys(Keys.ENTER) #回车键(Enter)
send_keys(Keys.CONTROL,‘a’) #全选(Ctrl+A)
send_keys(Keys.CONTROL,‘c’) #复制(Ctrl+C)
send_keys(Keys.CONTROL,‘x’) #剪切(Ctrl+X)
send_keys(Keys.CONTROL,‘v’) #粘贴(Ctrl+V)
send_keys(Keys.F1) #键盘 F1
send_keys(Keys.F12) #键盘 F12
二、自动化项目实战
1、需求分析与用例设计:深度挖掘需求,设计测试用例
2、项目架构设计:合理设计目录以及包结构:
Testcase测试用例:用来存放测试用例;
Data测试数据:数据驱动实现测试,用于存放数据;
Logs:log日志;
Config:配置文件;
Reports:测试报告;
Screenshots:截屏;
Lib:第三方库;
Utils:工具类;
Main.py:用于执行测试;
3、PyAutoGUI:图形用户界面自动化测试工具,通过X,Y坐标确定目标位置,控制鼠标键盘发送虚拟点击,完成按钮以及表单等操作;
Pyautogui.position():确定鼠标当前位置;
Pyautogui.moveTo(x,y[,duration=t]):移动;
举例:
from selenium import webdriver
from time import sleep
import pyautogui
'''
定位按钮时,元素定位技术无法定位时,可以选择使用pyautogui技术通过x,y坐标进行定位
'''
def test():
driver = webdriver.Chrome()
driver.get("http://jpress.io/user/register")
driver.maximize_window()
sleep(2)
elem = driver.find_element_by_id("agree")
rect = elem.rect #获取坐标
pyautogui.click(rect['x']+30,rect['y']+130)
sleep(4)
4、解决验证码验证问题:
1、通过pytesseract某块和PIL模块进行验证
具体步骤:1、获取整个页面;2、 获得验证码坐标位置数据;3、根据坐标位置抠图;4、使用pytesseract验证;
举例:
from selenium import webdriver
from PIL import Image
import time
import pytesseract
#获取验证码截图
def test1():
#打开谷歌浏览器
browser = webdriver.Chrome()
#打开首页
browser.get("http://localhost:8080/jpress/user/register")
browser.maximize_window()
#获取验证码图片
t = time.time()
picture_name_1 = str(t) + '.png'
browser.save_screenshot(picture_name_1)
ce = browser.find_element_by_id("captchaimg")
#获取位置信息
print(ce.location)
left = ce.location['x']
top = ce.location['y']
right = ce.size['width'] + left
height = ce.size['height'] + top
#扣图
im = Image.open(picture_name_1)
img = im.crop((left,top,right,height))
#保存为第二章图片
t = time.time()
picture_name_2 = str(t) + '.png'
img.save(picture_name_2)
browser.close()
#得到截图中的字符串
def test2():
#引入pytesseract方法识别图片中的验证码
picture_name_2 = 'test.png'
image_1 = Image.open(picture_name_2)
str = pytesseract.image_to_string(image_1)
#输出字符串
print(str)
2、通过第三方平台,AI算法识别:https://www.showapi.com/apiGateway/view/184?skuid=5f8e59a76e3607c363634c7e
5、完成用户注册功能测试用例(这点就直接编写测试用例,可以初始创建一个basic基础模块,用于封装用例,也为后期使用框架重构做准备)
6、pytest框架进行测试用例重构:简单灵活,支持参数化,可以支持简单的单元测试以及复杂的功能测试,具有丰富的第三方插件,集成selenium,集成html生成测试报告;
编写规则:
测试文件以test开头(以test结尾也可以)
测试类以test开头,并且不能带有init方法
测试函数以test开头
断言使用基本的assert就可以
控制台参数信息:-v---用于显示每个测试函数的执行结果
-s---用于显示测试函数中print()函数输出
-q---只显示整体测试结果
标记:可以标记用例或者函数哪些执行哪些不执行;
1、pytest查找策略:默认情况下pytest会递归查找以test开头或结尾的测试脚本,并执行文件内以test开始或结束的函数或方法;
2、标记测试函数:由于某种原因,我们想执行指定的函数用例,可以通过标记进行编写;
1、显示指定函数名,通过::标记:
控制台输入:pytest test01.py :: test01
2、使用模糊匹配,-k参数进行标识
控制台输入:pytest -k add(模糊查询的字段) test01.py
参数化设置:可以同时运行多个数据的测试:pytest.mark.parametrize
举例:
import pytest
# 列表
data = ['123', '456']
@pytest.mark.parametrize('pwd', data)
def test1(pwd):
print(pwd)
# 元组
data2 = [
(1, 2, 3), # 或者[1, 2,3]
(4, 5, 6) # 或者[4, 5,6]
]
@pytest.mark.parametrize('a, b, c', data2)
def test2(a, b, c):
print(a, b, c)
# 字典
data3 = (
{
'user': 1,
'pwd': 2
},
{
'user': 3,
'pwd': 4
}
)
@pytest.mark.parametrize('dic', data3)
def test3(dic):
print(dic)
data_1 = [
pytest.param(1, 2, 3, id="(a+b):pass"), # id的值可以自定义, 只要方便理解每个用例是干什么的即可
pytest.param(4, 5, 10, id="(a+b):fail")
]
def add(a, b):
return a + b
class TestParametrize(object):
@pytest.mark.parametrize('a, b, expect', data_1)
def test_parametrize_1(self, a, b, expect):
assert add(a, b) == expect
if __name__ == '__main__':
pytest.main(['-sv', 'test3.py'])
7、pytest fixture:使用fixture实现用例之间的一个调用;
在函数上加一个装饰器:@pytest.fixture()
fixture不能以test开头,与用例区分开,fixture有返回值,没有得话默认返回none;
调用fixture得返回值,就是直接把fixture得函数名当作变量名;
示例:
import pytest
@pytest.fixture()
def init():
print('init...')
return 1
def test1(init):
print('test1')
def test2(init):
print('test2')
if __name__ == '__main__':
pytest.main(['-s', '04 pytest Fixture.py']
8、pytest中setup与teardown:每次用例开始和结束都执行一次,可以之启动一次浏览器执行多个用例;
"""
模块级别:(setup_module/teardown_module)开始于模块的始末,全局的
函数级别:(setup_function/teardown_function)只对函数的用例生效,不在类中
类级别:(setup_class/teardown_class)只在类中前后运行一次(在类中,需要使用装饰器@classmethod)
方法级别:(setup_method/teardown_method)开始于方法始末(在类中)
类里面的:(setup/teardown)运行在调用方法的前后
所有级别名称必须写对
"""
import pytest
print("=========模块级别==========")
def setup_module():
print("setup_module")
def teardown_module():
print("teardown_module")
def test():
print("test")
print("=========函数级别==========")
def setup_function():
print("setup_function")
def teardown_function():
print("teardown_function")
def test01():
print("test01")
print("=========类级别==========")
class TestCase01(object):
@classmethod
def setup_class(cls):
print("setup_class")
@classmethod
def teardown_class(cls):
print("teardown_class")
def test03(self):
print("test03")
if __name__ == '__main__':
pytest.main('-sv','test07.py')
9、生成测试报告:
安装allure-pytest:pip install allure-pytest
电脑本地安装allure,配置环境变量
举例:
import allure
import pytest
@pytest.fixture(scope="session")
def login():
print("用例先登录")
@allure.step("步骤1:点xxx")
def step_1():
print("111")
@allure.step("步骤2:点xxx")
def step_2():
print("222")
@allure.feature("编辑页面")
class TestEditPage():
'''编辑页面'''
@allure.story("这是一个xxx的用例")
def test_1(self, login):
'''用例描述:先登录,再去执行xxx'''
step_1()
step_2()
print("xxx")
@allure.story("打开a页面")
def test_2(self, login):
'''用例描述:先登录,再去执行yyy'''
print("yyy")
if __name__ == '__main__':
# 注意生成测试报告 必须在命令行执行
#1、pytest --alluredir ./reports testcase/pytest/test6.py (目录一定找对)
#2、 allure serve reports
pytest.main(['--alluredir', './reports', 'test08.py'])
10、进行重构:
类中继承object;
setup方法改为pytest setup;
报告使用pytest插件;
断言延用python自带得断言;
使用pytest解决用例之间依赖关系:安装dependency:pip install pytest-dependency
使用时在需要依赖得用例上加入装饰器:@pytest.mark.dependency(name='xxxx')
11、selenium读取数据库数据:
安装mysqlclient
获得数据库连接
查询数据
实例:
import MySQLdb
import pytest
conn = MySQLdb.connect(
user='root',
passwd='123456',
host='localhost',
port=3306,
db='testing_db'
)
def get_data():
query_sql = 'select id,username,pwd from user_tb'
lst = []
try:
cursor = conn.cursor()
cursor.execute(query_sql)
r = cursor.fetchall()
for x in r:
u = (x[0], x[1], x[2])
lst.append(u)
return lst
finally:
cursor.close()
conn.close()
@pytest.mark.parametrize('id, name, pwd', get_data())
def test1(id, name, pwd):
print(id, name, pwd)
if __name__ == '__main__':
pytest.main(['-sv'])