pytest框架
学习目标
- 掌握pytest理论
- 熟练编写pytest框架
- 掌握pytest自带方法
- 掌握pytest常用插件
- 完成自动化代码代入框架练习
1. 什么是pytest
pytest是python自动化的一种单元测试框架
2. 特点
- 非常简单容易上手,入门简单,文档丰富
- 支持简单的单元测试,以及复杂的业务测试
- 支持参数化
- 可用指定跳过某些用例、对失败用例进行重试
- 很多第三方插件可用
3. 安装pytest
方法一:
文件-->设置-->项目-->解释器-->[+]-->搜索pytest-->安装
方法二:
打开终端运行命令:pip install pytest
使用pip list命令查看是否安装成功
4.pytest框架编码规范
- pytest框架规定,需要被执行的类,必须以Test开头
- pytest框架规定,需要被执行的测试用例(方法),方法名需要以test开头
1. pytest框架demo
import pytest
class TestDemo: # 需要被执行的类,需以“Test”开头,注意区分大小写
def test_01(self): # 需要被执行的方法(测试用例),需以“test”开头,注意区分大小写
a = 1+1 # 编写常规的方法体代码(测试用例的功能代码)
assert a == 2 # 断言,即该用例的预期结果
def test_02(self):
a = 1+1
assert a == 3
2. pytest运行方式
- 右键运行
- 点击代码左侧的绿色箭头
- 终端命令运行
- __main__方法执行
- pytest.ini配置文件运行
① 终端命令运行
语法:pytest -s -v 文件路径
案例:pytest -s -v .\pytest框架\demo.py
解释:-s 保留脚本代码中的输出print语句
-v 打印出被执行的类名、方法名
② __main__方法执行
- 新建一个main文件
- 编写以下代码:
import pytest
if __name__ == '__main__':
pytest.main(["-s","-v","Testdemo.py"])
③. pytest.ini运行pytest
- 新建一个文件夹:testCase
- 将需要执行的py文件放进testCase文件夹内
- 新建一个文件:pytest.ini
- 编写以下代码(不要在该文件内写注释或使用中文):
[pytest]
addopts = -s -v
testpaths = ./testCase
python_files = Test*.py
python_classes = Test*
python_functions = test*
解释:
[pytest] # pytest标识
addopts = -s -v # 追加配置参数
testpaths = ./testCase # 需要被执行的文件夹路径
python_files = Test*.py # 需要被执行的文件名格式
python_classes = Test* # 需要被执行的类名格式
python_functions = test* # 需要被执行的方法名格式
3. pytest框架自带方法
- setup_class:类初始化方法,类被执行时,第一个被执行的方法,只会执行一次
- teardown_class:类结束方法,类执行结束时,最后一个运行的方法,只会执行一次
- setup:用例初始化方法,每一条用例执行前都会执行一次
- teardown:用例结束方法,每一条用例执行后都会执行一次
将自带方法代入demo案例:
import pytest
class TestDemo02:
def setup_class(self):
print("类开始方法!")
def setup(self):
print("用例开始方法!")
def test_01(self):
print("第一条用例!")
assert True
def test_02(self):
print("第二条用例!")
assert False
def test_03(self):
print("第三条用例!")
assert True
def teardown(self):
print("用例结束方法!")
def teardown_class(self):
print("类结束方法!")
4. pytest常用插件
- pytest-html:自动生成html测试报告
- pytest-ordering:控制用例执行顺序
- pytest-rerunfailures:失败用例自动重试
- @pytest.mark.skipif:跳过不执行的用例
- @pytest.mark.parametrize:数据参数化
① pytest-html自动生成html测试报告
自动化脚本最终执行通过/不通过,都需要用测试报告来体现
- 安装插件:pip install pytest-html
- 新建一个文件夹:report
- 修改pytest.ini配置文件如下:
[pytest]
addopts = -s -v --html=report/report.html
testpaths = ./testCase
python_files = Test*.py
python_classes = Test*
python_functions = test*
运行pytest,会自动在report文件夹内生成一个report.html,使用浏览器打开页面可打开该页面
② pytest-ordering控制用例执行顺序
用例前后顺序会对用例实际执行效果产生影响
- 安装插件:pip install pytest-ordering
- 在需要被控制的用例前一行,使用修饰器:@pytest.mark.run(order=1)
@pytest.mark.run(order=1)
def test_03(self):
print("第三条用例!")
assert True
③ pytest-rerunfailures失败用例自动重试
为了避免因为环境波动问题导致用例执行失败,因此提供失败用例自动重试机制,当全部重试机会均为失败,用例才算失败
- 安装插件:pip install pytest-rerunfailures
- 修改pytest.ini配置文件如下:
[pytest]
addopts = -s -v --html=report/report.html --reruns 3
testpaths = ./testCase
python_files = Test*.py
python_classes = Test*
python_functions = test*
④ @pytest.mark.skipif跳过不执行的用例
在指定场景下,有部分用例不需要被执行,可设置为“跳过”
- 在需要跳过的用例前一行,添加修饰器:@pytest.mark.skipif(condition=True, reason='本版本不执行!')
@pytest.mark.skipif(condition=True,reason='本版本不执行!')
def test_04(self):
print("第四条用例!")
assert True
⑤ 数据参数化
数据写死经常达不到测试目的,需要对数据进行参数化
- 单一参数:@pytest.mark.parametrize('参数名', [值1, 值2, ...])
- 多参数:@pytest.mark.parametrize(('参数名1', '参数名2', ...), [(值1, 值2, ...), (值1, 值2, ...), ...])
@pytest.mark.parametrize('a',['黄焖鸡','红烧肉'])
def test_05(self,a):
print("第五条用例!")
print(a)
assert True
@pytest.mark.parametrize(('num1', 'num2', 'r'),[10, 20, 30])
def test_05(self,num1, num2, r):
print("第六条用例!")
sum = num1 + num2
assert sum == r
项目练习: 完成“宠物医院”的登录功能自动化
① 现有功能测试用例如下:
② 新建一个用例脚本文件:TestLogin.py
③ 若不使用pytest框架,最原始的代码大致如下:
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get('http://localhost:8080/')
'''登录失败(用户名空+密码空)'''
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('') # 用户名输入框输入空字符
pwd.send_keys('') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
user_name_msg = driver.find_element_by_class_name('userName-msg') # 定位用户名提示气泡
pwd_msg = driver.find_element_by_class_name('pass-msg') # 定位密码提示气泡
assert user_name_msg.text == '用户名不能为空' # 用户名提示气泡的内容=指定提示语
assert pwd_msg.text == '密码长度不能小于5个字符' # 密码提示气泡的内容=指定提示语
driver.refresh() # 刷新页面
'''登录失败(用户名空+密码正确)'''
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('') # 用户名输入框输入空字符
pwd.send_keys('123456') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
user_name_msg = driver.find_element_by_class_name('userName-msg') # 定位用户名提示气泡
assert user_name_msg.text == '用户名不能为空' # 用户名提示气泡的内容=指定提示语
driver.refresh() # 刷新页面
'''登录失败(用户名正确+密码空)'''
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('admin') # 用户名输入框输入空字符
pwd.send_keys('') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
pwd_msg = driver.find_element_by_class_name('pass-msg') # 定位密码提示气泡
assert pwd_msg.text == '密码长度不能小于5个字符' # 密码提示气泡的内容=指定提示语
driver.refresh() # 刷新页面
'''登录失败(用户名正确+密码错误)'''
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('admin') # 用户名输入框输入空字符
pwd.send_keys('111111') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
msg = driver.find_element_by_class_name('layui-layer-padding') # 定位报错弹窗
assert msg.text == '用户名或密码错误' # 密码提示气泡的内容=指定提示语
driver.refresh() # 刷新页面
'''登录失败(用户名错误+密码正确)'''
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('root123') # 用户名输入框输入空字符
pwd.send_keys('123456') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
msg = driver.find_element_by_class_name('layui-layer-padding') # 定位报错弹窗
assert msg.text == '用户名或密码错误' # 密码提示气泡的内容=指定提示语
driver.refresh() # 刷新页面
'''登录失败(用户名错误+密码错误)'''
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('root123') # 用户名输入框输入空字符
pwd.send_keys('111111') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
msg = driver.find_element_by_class_name('layui-layer-padding') # 定位报错弹窗
assert msg.text == '用户名或密码错误' # 密码提示气泡的内容=指定提示语
driver.refresh() # 刷新页面
'''登录成功'''
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('admin') # 用户名输入框输入空字符
pwd.send_keys('123456') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(2)
msg = driver.find_element_by_xpath('/html/body/table/tbody/tr[1]/td/div/table/tbody/tr/td[3]/div/span[1]') # 定位温馨提示
assert msg.text == '你好!' # 登录成功后的温馨提示=指定提示语
time.sleep(1)
driver.quit()
⑤ 代入pytest框架,代码大致如下:
import pytest
from selenium import webdriver
import time
class TestLogin:
def setup_class(self):
driver = webdriver.Chrome()
driver.get('http://localhost:8080/')
def setup(self):
driver.refresh()
# 用户名空+密码空
def test_01(self):
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('') # 用户名输入框输入空字符
pwd.send_keys('') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
user_name_msg = driver.find_element_by_class_name('userName-msg') # 定位用户名提示气泡
pwd_msg = driver.find_element_by_class_name('pass-msg') # 定位密码提示气泡
assert user_name_msg.text == '用户名不能为空' # 用户名提示气泡的内容=指定提示语
assert pwd_msg.text == '密码长度不能小于5个字符' # 密码提示气泡的内容=指定提示语
# 用户名空+密码正确
def test_02(self):
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('') # 用户名输入框输入空字符
pwd.send_keys('123456') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
user_name_msg = driver.find_element_by_class_name('userName-msg') # 定位用户名提示气泡
assert user_name_msg.text == '用户名不能为空' # 用户名提示气泡的内容=指定提示语
# 用户名正确+密码空
def test_03(self):
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('admin') # 用户名输入框输入空字符
pwd.send_keys('') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
pwd_msg = driver.find_element_by_class_name('pass-msg') # 定位密码提示气泡
assert pwd_msg.text == '密码长度不能小于5个字符' # 密码提示气泡的内容=指定提示语
# 用户名正确+密码错误
def test_04(self):
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('admin') # 用户名输入框输入空字符
pwd.send_keys('111111') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1.5)
msg = driver.find_element_by_class_name('layui-layer-padding') # 定位报错弹窗
assert msg.text == '用户名或密码错误' # 报错弹窗的内容=指定提示语
# 用户名错误+密码正确
def test_05(self):
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('root123') # 用户名输入框输入空字符
pwd.send_keys('123456') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
msg = driver.find_element_by_class_name('layui-layer-padding') # 定位报错弹窗
assert msg.text == '用户名或密码错误' # 报错弹窗的内容=指定提示语
# 用户名错误+密码错误
def test_06(self):
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('root123') # 用户名输入框输入空字符
pwd.send_keys('11111') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(1)
msg = driver.find_element_by_class_name('layui-layer-padding') # 定位报错弹窗
assert msg.text == '用户名或密码错误' # 报错弹窗的内容=指定提示语
# 用户名正确+密码正确
def test_07(self):
user_name = driver.find_element_by_id('name') # 定位用户名输入框
pwd = driver.find_element_by_id('password') # 定位密码输入框
login = driver.find_element_by_class_name('input3') # 定位登录按钮
user_name.send_keys('admin') # 用户名输入框输入空字符
pwd.send_keys('123456') # 密码输入框输入空字符
login.click() # 点击登录按钮
time.sleep(2)
msg = driver.find_element_by_xpath('/html/body/table/tbody/tr[1]/td/div/table/tbody/tr/td[3]/div/span[1]') # 定位温馨提示
assert msg.text == '你好!' # 登录成功后的温馨提示=指定提示语
def teardown(self):
pass
def teardown_class(self):
driver.quit()