自动化-Notes
常用命令
#对pip进行升级
python -m pip install --upgrade pip
#selenium安装:
pip install selenium==版本号
pip install selenium==错误的版本号,会显示所有可安装的版本
#查看版本
pip show selenium
概念
1、web自动化测试
- 让程序代替人工自动验证web项目功能的过程
2、什么Web项目适合做自动化测试
-
需求变动不频繁
-
项目周期长
-
项目需要回归测试
3、web自动化开始进行阶段
- 手工测试之后(1,时间问题2,功能不完善)
4、自动化测试分类
-
web自动化测试
-
移动自动化测试(app自动化)
-
接口自动化(工具,代码)
-
单元测试
5、web自动化测试所属分类(代码可见度)
-
黑盒测试(功能测试)
-
白盒测试(单元测试)
-
灰盒测试(接口测试)
6、web自动化测试属于黑盒测试(功能测试)
7、主流测试工具
- QTP 收费(支持web,自动化)
- selenium(免费,开源,只支持web项目)
- Robot fromwork:基于python扩展关键字驱动
8、selenium:一个web自动化测试工具
特点:
-
开源,免费
-
跨平台(Linux , windows, mac)
-
支持多浏览器:火狐,谷歌,ie
-
支持多语言:python ,Java,c
-
成熟稳定
-
功能强大,支持商业化大部分功能,并且由于开源,可以定制化需求功能
9、元素定位依赖于
- 标签名
- 属性
- 层级
- 跨径
定位方式
- id
- name
- class_name
- tag_name
- link_text
- partial_link_text
- xpath
- css
# 引入selenium库相关模块
from time import sleep
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.by import By
# 实例化Edge浏览器的webdriver对象
driver = webdriver.Edge()
try:
# 打开本地注册页面
url = "file:///D:/Repositories/GitCode/html_login_register/register.html"
driver.get(url)
# id定位元素并填写表单
driver.find_element(By.ID,"username").send_keys("admin")
driver.find_element(By.ID,"password").send_keys("123456")
driver.find_element(By.ID,"password2").send_keys("123456")
#name定位元素并填写表单
#driver.find_element(By.NAME,"username").send_keys("admin")
#driver.find_element(By.NAME,"password").send_keys("123456")
#driver.find_element(By.NAME,"password2").send_keys("123456")
#class_name定位元素并填写表单(实际写入的是class属性值)
#driver.find_element(By.CLASS_NAME,"form-control").send_keys("admin")
#driver.find_element(By.CLASS_NAME,"form-control").send_keys("123456")
#driver.find_element(By.CLASS_NAME,"form-control").send_keys("123456")
#tag_name定位元素并填写表单(写入input)
#driver.find_element(By.TAG_NAME,"input").send_keys("admin")
#link_text(精准匹配)与partial_link_text(模糊匹配)定位超链接a标签
#driver = webdriver.Edge()
#url = "https://www.runoob.com/"
#driver.get(url)
#driver.find_element(By.LINK_TEXT,"【学习 HTML】XXXX").click()
#driver.find_element(By.PARTIAL_LINK_TEXT,"【学习 HTML】").click()
#xpath定位元素并填写表单
#driver.find_element(By.XPATH,"/html/body/div[@id='center']/form[@id='myform']/div[@class='input-group'][1]/input[@id='username']").send_keys("admin")
#driver.find_element(By.XPATH,"/html/body/div[@id='center']/form[@id='myform']/div[@class='input-group'][2]/input[@id='password']").send_keys("123456")
#CSS定位元素并填写表单
#driver.find_element(By.CSS_SELECTOR,"#username").send_keys("admin")
#driver.find_element(By.CSS_SELECTOR,"input#password.form-control").send_keys("123456")
#driver.find_element(By.CSS_SELECTOR,"#password2").send_keys("123456")
# 等待3秒
sleep(3)
# 捕获WebDriverException异常(可能由于网络、浏览器驱动等原因导致)
except WebDriverException as e:
print(e)
finally:
# 关闭WebDriver
driver.quit()
为什么使用XPATH和css 定位
-
id,name,class依赖于这三个元素对应的属性,如果元素没有以上三个属性,定位方法不能使用
-
link_text和partial_link_text只适合超链接
-
tag_name:只能找页面唯一元素,或者多个相同元素中的第一个元素
11、汇总:
-
基于元素属性特有定位方式(id/name/class_name)
-
基于元素标签名称定位:tag_name
-
定位超链接文本(link_text,pattial_link_text)
-
基于元素路径定位(xpath)
-
基于选择器(css)
浏览器常用API
-
driver.maximize_window() 窗口最大化
-
driver.set_window_size(w,h) 设置窗口大小
-
driver.set_window_position(x,y)设置窗口位置
-
driver.back() 后退
-
driver.forward() 前进
-
driver.refresh()刷新
-
driver.close()关闭当前窗口
-
driver.quit()关闭驱动对象
-
driver.title获取页面title
-
driver.current_url获取当前页面url
# 导入sleep函数
from time import sleep
# 导入WebDriverException
from selenium.common.exceptions import WebDriverException
# 导入webdriver模块
from selenium import webdriver
# 导入By类
from selenium.webdriver.common.by import By
# 实例化Edge浏览器的webdriver
driver = webdriver.Edge()
try:
# 指定URL并打开
url = "file:///D:/Repositories/GitCode/html_login_register/login.html"
driver.get(url)
# 最大化浏览器窗口
driver.maximize_window()
sleep(2)
# 设置浏览器窗口大小
driver.set_window_size(500,300)
sleep(2)
# 设置浏览器窗口位置
driver.set_window_position(320,150)
# 根据CSS选择器找到注册按钮元素并点击
driver.find_element(By.CSS_SELECTOR,"#register").click()
sleep(2)
# 返回上一个页面
driver.back()
sleep(2)
# 前进到下一个页面
driver.forward()
sleep(2)
# 捕获WebDriverException异常并打印
except WebDriverException as e:
print(e)
# 关闭webdriver
finally:
driver.quit()
获取元素信息
-
driver.size 返回元素大小
-
driver.text 返回元素的文本
-
driver.get_attribute("id") 获取属性值,传递的参数为元素的属性名
-
element.is_displayed() 判断元素是否可见
-
element.is_enabled() 判断元素是否可用
-
element.is_selected() 判断元素是否选中,用来检查复选框或单选按钮是否被选中
test和size调用时无括号
get_attribute一般应用场景:判断一组元素是否为想要的元素或者判断元素属性值是否正确
is_displayed,is_enabled,is_selected在特殊应用场景中使用
鼠标操作
提示:selenium框架中,虽然提供了鼠标右击方法,但是没有提供选择右击菜单的方法,可以通过发送快捷键的方式解决(经测试,谷歌浏览器不支持)
#导包
from selenium.webdriver.common.action_chains import ActionChains
#实例化
action = ActionChains(driver)
#鼠标事件常用的操作方法:
1.context_click() #右击
应用:action.contex_click(元素定位).perform()
2.double_click() #双击
应用:action.double_click(元素定位).perform()
3.drag_and_drop() #拖拽
应用:action.drag_and_drop(控制的元素,指定位置).perform()
4.move_to_element() #悬停
应用:action.move_to_click(元素定位).perform()
5.perform() #执行以上事件方法
键盘操作
#导包
from selenium.webdriver.common.keys import Keys
#定位用户名
username=driver.find_element(By.NAME,"username")
#输入文本
username.send_keys("15679790909")
#删除文本
username.send_keys(Keys.BACK_SPACE)
#全选文本
username.send_keys(Keys.CONTROL,"a")
#复制文本
username.send_keys(Keys.CONTROL,"c")
#粘贴文本
driver.find_element(By.NAME,"password").send_keys(Keys.CONTROL,"v")
元素等待
-
为什么设置元素等待:由于网络或配置,未第一时间加载出来,而抛出未找到元素异常
-
什么是元素等待:元素在第一次未找到时,元素等待设置的时长被激活,如果在设置的有效时长内找到元素,继续执行代码,如果超出设置的时长未找打元素,抛出未找到元素异常
-
元素等待分类:1、隐式等待 2、显示等待
隐式等待(全局)
driver.implicitly_wait(timeout)
#(timeout:为等待最大时长,单位秒)
显示等待(局部)
导包->from selenium.webdriver.support.wait import webDriverWait
#参数:
#timeout : 超时时间
#poll frequency : 访问频率,默认0.5秒
#x: x 为driver,它是WebDriverWait类将传入的driver赋值给类self._driver,until方法调用了self.driver
WebDriverWait(driver,timeout=10,poll_frequency=0.1).until(lambda x:x.find_element(By.NAME"username")).send_keys("15679790909")
扩展
send_keys("文件名") 可以上传文件
driver.find_element(By.NAME,"password").send_keys("D:\hello.txt")
忽略警告
import warnings
warnings.filterwarnings("ignore")
API操作
下拉框
可以使用css直接定位
缺点:如果option选项没有value值的话,css定位或其他定位就不太方便
解决:select类
#1.导包:from selenium.webdriver.suport.select import Select
#2.实例化:s=Select(element)
#3.调用方法:s.select_by_index()
select_by_index(1) #通过下标索引定位
select_by_value("sh") # 通过value值
select_by_visible_text("上海") # 通过文本
注意事项:
- 实例化select时,需要的参数为select标签元素
- 调用Select类下面的方法,是通过索引,value属性值,显示文本去控制,而不需要click()
警告框
对话框类型
-
alert 警告框
-
confirm 确认框
-
prompt 提示框
如何处理:
步骤:
1.切换到对话框
方法:driver.switch_to.alert
2.处理对话框
driver.switch_to.alert.text 获取文本
driver.switch_to.alert.accept() 同意
driver.switch_to.alert.dismiss() 取消
滚动条
selenium 中没有直接定位滚动条的方法,可以通过js语句间接控制
操作
1.设置js语句:
js="window.scrollTo(0,1000)"
0:x轴向右 1000:y轴向下
2.调用js方法
driver.execute_script(js)
切换Frame表单
frame,iframe
为什么切换?
当前主目录内没有iframe表单页面元素信息,不切换,找不到元素
如何切换
方法:driver.switch_to.frame("id\name\element")
为什么要回到主目录:
iframe或frame只有在主目录采用相关元素信息,不回到主目录,切换语句会报错
如何回到主目录:
方法:driver.switch_to.default_content()
driver.switch_to.parent_frame()
切换frame时,可以使用name,id,iframe元素
多窗口切换
为什么要切换多窗口
页面存在多个窗口时,selentium默认焦点只会在主窗口上的所有元素,不切换窗口,无法操作主窗口以外的窗口元素
如何切换
思路:获取要切换的窗口句柄,调用切换方法进行切换
方法:
1. driver.current_window_handle 获取当前主窗口句柄
2. driver.window_handles 获取当前由driver启动的所有窗口句柄
3. driver.switch_to.window(handle) 切换到指定窗口
#步骤:
1. 获取当前窗口句柄
2. 点击连接,启动另一个窗口
3. 获取当前所有窗口句柄
4. 遍历所有窗口句柄
5. 判断当前遍历的窗口句柄不等于主窗口句柄
6. 切换窗口操作
#示例
handle=diver.current_window_handle
i=diver.window_handles
for j in i:
if j!=handle:
diver.switch_to.window(j)
截屏
方法:
driver.get_screenshot_as_file(imagepath)
多次产生截图,可以使用时间戳的形式进行区分
操作:
#导包->import datetime
#strftime:将时间转为字符串函数
driver.get_screenshot_as_file('../Img/%s.png'%(datetime.strftime("%Y_%m_%d %H_%M_%S")))
验证码
作用:防止恶意请求
处理方式
1.去掉验证码;项目在测试环境,公司自己的项目
2.设置万能验证码;测试环境或线上环境,公司自己的项目
3.使用验证码识别技术;识别效率低,不推荐
4.使用cookie;推荐
cookie
由服务器生成:
作用:标记一次对话的状态(登录的状态)
使用:浏览器自动记录cookie,在下一条请求时将cookie信息自动附加请求
应用:
方法:driver.get_cookie() 获取所有的coolie
driver.add_cookie({字典}) 设置cookie
#步骤:
#1. 打开百度url driver.get("http://www.baidu.com")
#2. 设置cookie信息: driver.add_cookie({"name":"BDUSS","value":"根据实际情况编写"})
#3. 暂停2秒以上
#4. 刷新操作
from time import sleep
from selenium import webdriver
driver = webdriver.Edge()
driver.get("https://www.baidu.com/")
# 创建字典存储 cookie
cookie_dict = {
"name": "BDUSS",
"value": "xxxx"
}
# 添加 cookie 到 WebDriver
driver.add_cookie(cookie_dict)
sleep(5)
#获取所有cookies信息
cookies = driver.get_cookies()
print("cookies信息为:",cookies)
print('-----------------------')
for cook in cookies:
print(cook['name'])
#刷新,必须进行刷新才能看到效果
driver.refresh()
driver.implicitly_wait(3)
driver.quit()
UnitTest框架
特点
-
批量执行用例
-
提供丰富的断言知识
-
可以生成报告
python自带的一种单元测试框架
核心要素
-
TestCase测试用例
-
TestSuite测试套件
-
TextTestRunner以文本的形式运行测试用例
-
TestLoader批量执行测试用例-搜索指定文件夹内指定字母开头的模块
-
Fixture固定装置,两个固定的函数,一个初始化使用,一个结束的时候使用
TestCase
说明:测试用例
步骤:
- 导包->import unittest
- 定义测试类->新建测试类必须继承unittest.TestCase
- 定义测试方法->测试方法命名必须以test开头
运行:
1.运行测试类所有的测试方法,光标定位到类当前行右键运行
2.运行单个测试方法:光标放到测试方法当前行。
#Demo:编写求和函数
#导包
import unittest
#编写求和函数
def add(x,y):
return x+y
#定义测试类并继承
class Test01(unittest.TestCase):
#定义测试方法 注意:以test字母开头
def test_add(self):
#调用测试的函数
result = add(1,1)
print("结果为:",result)
def test_add02(self):
#调用测试的函数
result = add(1,2)
print("结果为:",result)
print("__name__内置变量获取当前运行的模块名称:",__name__)
# __name__:python中内置变量
# 1、如果当前运行的模块是当前模块:__name__的值为:__main__
# 2、如果当前运行的模块不是主模块:__name__的值为:模块名称(只要进行了导包并引用)
if __name__ == '__main__':
unittest.main()
Test Suite
提示:需要配合TestRunner才能被执行
说明:测试套件
步骤:
- 导包
- 获取测试套件对象,suite = unittest.TestSuite()
- 调用addTest()方法,添加测试用例
添加测试用例方法:
- suite.addTest(类名("方法名称")) #添加指定类中指定的测试方法
- suite.addTest(unittest.makeSuite(类名)) #添加指定类中所有以test开头的方法
#导包
import unittest
from WebTest.UnitTest框架.test_01_TestCase import Test01
from WebTest.UnitTest框架.test02 import Test02
if __name__ == '__main__':
#实例化suite对象
suite = unittest.TestSuite()
#调用添加方法
#写法一 类名("方法名") 注意:方法名称使用双引号
suite.addTest(Test01("test_add"))
suite.addTest(Test01("test_add02"))
#扩展:添加测试类中所有test开头的方法
suite.addTest(unittest.makeSuite(Test02))
#执行测试套件
runner = unittest.TextTestRunner()
runner.run(suite)
TextTestRunner
说明:执行测试套件方法
步骤:
- 导包
- 实例化后去执行套件对象 runner = unittest.TextTestRunner()
- 调用run方法执行runner.run(suite)
TestLoader
说明:
1、将符合条件的测试方法添加到测试套件中
2、搜索指定文件夹下指定字母开头的模块下test开始的方法,并将这些方法添加到测试套件中,最后返回测试套件
操作:
-
导包
-
调用Test Loader()
-
执行测试套件
- suite = unittest.TestLoader().discover("目录",“指定字母开头模块文件”)
import unittest
#调用方法,查找cases目录下的所有py文件
suite01 = unittest.TestLoader().discover("./cases")
#扩展:查找cases目录下所有以test开头的py文件
suite02 = unittest.TestLoader().discover("./cases",pattern="test*.py")
#扩展:defaultTestLoader=TestLoader(),注意:没有括号
suite03 = unittest.defaultTestLoader.discover("./cases")
#执行测试套件方法
unittest.TextTestRunner().run(suite03)
TestSuite和TestLoader区别
共同点:都是测试套件
不同点:实现方式不同
-
TestSuite:要么添加指定的测试类中所有test开头的方法,要么添加指定测试类中指定某个test开头的方法
-
TestLLoader:搜索指定目录下指定字母开头的模块中以test字母开头的方法并将这些方法添加到测试套件中,最后返回测试套件
Fixture
说明:装置函数(setUp、tearDown)
级别:
-
函数级别:def setUp() / def tearDown()
-
类级别:def setUpClass() / def dearDownClass()
-
模块级别:def setUpModule() / sef tearDownModule()
提示:无论使用函数级别还是类级别,最后常用场景为:
初始化:
-
获取浏览器实例化对象
-
最大化浏览器
-
隐式等待
结束:
- 关闭浏览器驱动对象
#fixture其实就是两个函数,这两个函数可以一起使用,也可以单独使用
# 1、初始化函数:def setUp()
# 2、结束函数:def tearDown()
# fixture级别:
# 1、函数级别(常用)
# 2、类级别
# 3、模块级别(常用)
# 引入unittest模块
import unittest
# 定义初始化模块函数setUpModule()
def setUpModule():
print("setUpModule")
# 定义结束模块函数tearDownModule()
def tearDownModule():
print("tearDownModule")
# 定义测试类Test03
class Test03(unittest.TestCase):
# 定义初始化类方法setUpClass()
@classmethod
def setUpClass(cls) -> None:
print("setUpClass被执行")
# 定义结束类方法tearDownClass()
@classmethod
def tearDownClass(cls) -> None:
print("tearDownClass被执行")
# 定义初始化函数setUp()
def setUp(self) -> None:
print("setUp被执行")
# 定义结束函数tearDown()
def tearDown(self) -> None:
print("tearDown被执行")
# 定义第一个测试函数test01()
def test01(self):
print("test01被执行")
# 定义第二个测试函数test02()
def test02(self):
print("test02被执行")
#执行顺序:模块>类>函数
# setUpModule
# setUpClass被执行
# setUp被执行
# test01被执行
# tearDown被执行
# setUp被执行
# test02被执行
# tearDown被执行
# tearDownClass被执行
# tearDownModule
UnitTest断言
什么是断言
- 让程序代替人工判断执行结果是否与预期结果相等的过程
为什么要断言
- 自动化不写断言,相当于没有执行
常用断言
-
self.assertEqual(a,b) 判断a是否等于b
-
self.assertIn(a,b) 判断b是否包含a
-
self.assertTure(a)判断a是否为True
import unittest
#unittest常用断言
# 1、asserTrue:如果结果为True通过,否则失败
# 2、assertEqual:判断两个字符串是否相等
# 3、assertIn:判断后边的字符串是否包含前边的字符串
# 4、assertIsNone:判断是否为None
class Test02(unittest.TestCase):
def test001(self):
# 断言是否为True
flag = True
flag =False
self.assertTrue(flag)
self.assertFalse(flag)
# 判断两个字符串是否相等
# self.assertEqual("hello","hell0")
# 判断后边的字符串是否包含前边的字符串
# self.assertIn("hello jack","hello jack,joker")
#判断是否为None
# flag = None
# self.assertIsNone(flag)
# self.assertIsNotNone(flag)
Demo
输入错误密码进行断言捕获异常
import unittest
from selenium import webdriver
from time import sleep
from datetime import datetime
from selenium.webdriver.common.by import By
#定义测试类并继承unittest.TestCase
class Test_YML(unittest.TestCase):
#定义初始化方法
def setUp(self) -> None:
#获取浏览器驱动对象
self.driver = webdriver.Edge()
#打开url
self.driver.get("http://192.168.226.143:8080/EasyBuy/Login?action=loginOut")
#最大化浏览器
self.driver.maximize_window()
#隐式等待
self.driver.implicitly_wait(10)
def tearDown(self) -> None:
#关闭浏览器
sleep(2)
self.driver.quit()
def test_login_code_null(self):
driver = self.driver
#点击登录链接
driver.find_element(By.PARTIAL_LINK_TEXT,"登录").click()
#输入用户名
driver.find_element(By.CSS_SELECTOR,"#loginName").send_keys("szz")
#输入密码
driver.find_element(By.CSS_SELECTOR,"#password").send_keys("1234")
#点击登录
driver.find_element(By.CSS_SELECTOR,".log_btn").click()
#获取登录后提示信息
result = driver.find_element(By.XPATH,".//*[@id='showMessage']").text
print("result:",result)
#定义预期结果
expect_result = "密码错误"
try:
#断言
self.assertEqual(result,expect_result)
#只捕获断言错误
except AssertionError:
#截图
driver.get_screenshot_as_file("../Img/{}.png".format(datetime.strftime("%Y_%m_%d %H_%M_%S")))
#抛出异常
raise
扩展
断言有两种方法:
方法1:unittest框架中断言
方法2:使用python自带的断言
- assert a==b 判断a是否等于b
- assert a in b 判断 b是否包含a
- assert True/1 判断是否为true
参数化
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.by import By
#字典参数化
user_dict = {
"admin":"admin",
"124":"124",
"125":"125",
"126":"126",
"127":"127",
"128":"128"
}
for username,password in user_dict.items():
driver = webdriver.Edge()
driver.get("http://192.168.226.141:8080/hr/index.do")
driver.find_element(By.ID,"username").send_keys(username)
driver.find_element(By.ID,"password").send_keys(password)
driver.find_element(By.CLASS_NAME,"right-button01").click()
print("当前登录用户:%s,密码:%s"%(username,password))
sleep(2)
driver.refresh()
driver.quit()
#元组参数化
# user_Tuple = (
# 111,
# 222,
# 333,
# 444
# )
# for username in user_Tuple:
# driver = webdriver.Edge()
# driver.get("http://192.168.226.141:8080/hr/index.do")
# driver.find_element(By.ID,"username").send_keys(username)
# driver.find_element(By.ID, "password").send_keys("1234")
# driver.find_element(By.CLASS_NAME, "right-button01").click()
# print("当前登录用户:%s"%username)
# sleep(2)
# driver.refresh()
# driver.quit()
#数据分离式参数化
# import data
# for username,password in data.user_dict.items():
# driver = webdriver.Edge()
# driver.get("http://192.168.226.141:8080/hr/index.do")
# driver.find_element(By.ID,"username").send_keys(username)
# driver.find_element(By.ID,"password").send_keys(password)
# driver.find_element(By.CLASS_NAME,"right-button01").click()
# print("当前登录用户:%s,密码:%s"%(username,password))
# sleep(2)
# driver.refresh()
# driver.quit()
解决冗余问题
根据需求动态获取参数并引用
解决相同业务逻辑,不同测试数据问题
应用插件
导包:from parameterized import parameterized
修饰测试函数 @parameterized.expand(数据)
数据格式
1.单个参数,类型为列表
2.多个参数,类型为列表嵌套元组
3.在测试函数中的参数设置变量引用参数值,变量的数量必须和数据值的个数相同
class testCae(unittest.TestCase):
@unittest.expectedFailure("1","2","3")
def test_add(self,num):
resukt =add(2,3)
print(num)
跳过方法
分类:
直接跳过:语法:@unittest.skip(说明)
一般功能为实现完成用例
条件满足跳过:语法:@unittestif.skip(说明)
判断条件满足,就不执行
以上两种都可以修饰类和函数
HTML测试报告
根据Text Test Runner改编而来
操作
- 导包 ->from xx.HTMLTestRunner import HTMLTestRunner
- 定义测试套件suite=unittest.defaultTestLOader.discover("../casse",patten="test*.py")
- 实例化HTMlTestRunner类,并调用run方法执行测试套件
with open(报告存放路径,“wb”)as f
注:生成html报告,必须使用wb,以二进制形式写入
- 实例化HTMLTestRunner类
HTMLTestRunner(stream=f).run(测试套件)
import unittest
from Tools.HTMLTestRunner import HTMLTestRunner
from datetime import datetime
case = unittest.defaultTestLoader.discover("./Case",pattern="test_hr.py")
if __name__ == '__main__':
report_dir = './Report/{}.html'.format(datetime.now().strftime("%Y_%m_%d %H_%M_%S"))
with open(report_dir,"wb") as f:
runner = HTMLTestRunner(stream=f,verbosity=1,title="人力资源管理系统测试报告",description="Test Case Result:")
runner.run(case)
f.close()
PO模式
版本
- V1:不采用任何模式(线性模型)
- V2:采用测试框架unittest
- V3:业务代码和页面对象进行
- V4:实际中的po模式编写
案例
- 账号不存在
- 密码错误
问题
v1无法批量运行
v2业务脚本和页面对象没有分开
v3代码冗余量大
PO介绍
PO:page(页面) object(对象)
v4版本
page继承base,scripts调用page
结构:
1、base(基类):page页面一些公共的方法;
- 初始化方法
- 查找元素对象
- 点击元素对象
- 输入方法
- 获取文本方法
- 截图方法
2、page(页面对象):一个页面封装成一个对象;
应用:继承base;
3、scripts(业务层):导包调用page页面;
注意:
以上方法封装的时候,解包只需一次,在查找元素解包
driver为虚拟,谁调用base时,谁传入,无需关注从哪来
loc真正使用loc的方法只有查找元素方法使用
2.page(页面对象):一个页面封装成一个对象
应用:继承base
实现:
- 模块名。page+实际操作模块名称 如:page_login.py
- 页面对象名:以大驼峰方法将模块名抄进来,有下划线的去掉下划线
- 方法:涉及元素,将每个元素操作单独封装一个操作方法
- 组装:根据需求组装以上操作步骤:
3.scripts(业务对象):导包,调用page页面
实现:
- 模块:test+实际操作模块名称 如:test login.py
- 测试业务名称,以大驼峰方法将模块名抄进来,有下划线的去掉下划线
- 方法:
初始化方法:setup()
实例化页面对象
前置操作:如打开等等
结束方法 tearDown()
关闭驱动
测试方法:根据要操作的业务来实现
扩展:loc变量:类型为元组,*loc为解包
数据驱动:
说明:通过测试数据控制用例的执行,直接影响测试结果
数据驱动是最好结合po+参数化技术使用
优点:将维护关注点放到测试数上,而不去关注测试脚本代码
数据驱动常用的格式:
- json
- Excel
- csv
- txt
json介绍
- 一种纯文本格式,后缀.json:
- 一种轻量级数据交换格式:(接口数据传递基本使用json格式)
- 由键值对组成,和python的字典格式一模一样,不同之处在于(json是文本格式)
- json语法:花括号包含键值对,键与值之间使用冒号(:)分隔,键值对之间使用逗号(,)分隔
json与字典转换
字典转为json字符串
方法:json.dumps()
字符串转字典
方法:json.loads()
json的写与读
需要导包
写入:方法:demp(写什么文件,往哪写)
读取:方法:load()
查找元素判断是否操作成功 思路封装
def base_if_success():
try:
self.base_find_element(loc,timeout=2)
return True
except:
return Palse
如何区分正向逆向用例
思路:在测试数据中添加一个表示正向或逆向用例的标记:如:True/False
步骤:
1.调用登录方法(此登录方法中,只有输入用户名,输入密码,输入验证码,点击验证码,点击登录按钮)切记:不要封装点击登录链接地址:
2.判断是否正向用例:
判断安全退出是否存在
点击安全退出
点击登录链接地址
否则
获取异常信息
断言操作
点击异常提示框确定按钮
日志
说明:记录系统运行程序一些步骤,对一个事件(点击事件),也称为日志
特点:
- 调试程序
- 定位跟踪bug
- 根据日志,查看系统运行是否出错
- 分析用户行,与数据统计
级别:
- debug调试级别
- info信息
- warning警告
- error错误
- critical严重
开发常用以上:debug,info,warning,error
测试常用级别:info,error
logging的基本使用
步骤:
- 导包
- 调用相应的级别方法,记录日志信息 logging.debug("debug.....")
设置级别
logging.basicConfig(level=logging.DEBUG)
提示:
- 默认级别为:logging.WARNING
- 设置级别是调用的是logging文件夹下面的常量,而不是调用的小写方法
- 切记:设置级别后,日志信息只会记录大于等于此级别的信息

浙公网安备 33010602011771号