pytest基础功能
pytset功能及使用示例
1.assert
断言
借助python的运算符号和关键字实现不同数据类型的断言
例如当前需要测试登录功能,一下是一个登录示例
python
# 注意运行示例之前请确认已经配置好浏览器的webdriver,使得python代码可以调用
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
"""
借助python的运算符号和关键字实现不同数据类型的断言
"""
# 某网站登录案例
def test_login_success():
# 初始化WebDriver(以Chrome为例)
driver = webdriver.Chrome()
# 打开测试网页
driver.get("https://www.taobao.com/")
# 找到登录按钮
login_element = driver.find_element(By.XPATH, '//*[@id="J_SiteNavLogin"]/div[1]/div[1]/a[1]')
# 点击登录按钮
login_element.click()
# 跳转到登录页面
# 获取用户名、密码输入框
username = driver.find_element(By.ID, "fm-login-id")
password = driver.find_element(By.ID, "fm-login-password")
# 输入用户名、密码
username.send_keys("username")
password.send_keys("password")
# 点击登录按钮
login = driver.find_element(By.XPATH, '//*[@id="login-form"]/div[6]/button')
# 休眠等待
sleep(10)
login.click()
# 或者使用回车(似乎淘宝不能使用回车登录)
# login.send_keys(Keys.RETURN)
# == 测试相等
# 登录成功检查
# 获取淘x中登陆成功后与登陆前不同之处,这里我使用了一个购物车字段
text = driver.find_element(By.XPATH,'//*[@id="ice-container"]/div[3]/div[2]/div/div[2]/div/div[1]/div[1]/a[2]/span/strong[2]').text
print(text)
# 休眠等待
sleep(3)
assert text == "tao昵称"
# 退出浏览器
driver.quit()
以上功能是针对登录案例编写的一段测试用例,因为不断尝试访问触发的淘宝的保护机制,这里便没有登录成功的截图。
python
# 常用比较方法
# != 测试不等于
# <= 测试小于等于
# >= 测试大于等于
# not in 测试不包含
# in 测试包含
还有一种比较抽象的想法
判断是否为ture
判断是否不为true
用代码解释
python
# 假设我们有一个简单的函数,它根据输入返回True或False
def is_even(number):
return number % 2 == 0
# 接下来,我们编写一个pytest测试来验证这个函数
import pytest
def test_is_even():
# 使用assert来断言is_even(2)返回True
assert is_even(2)
# test_is_even函数通过assert语句来验证is_even函数的行为是Ture还是False
2.参数化
当一组测试用例有固定的测试数据时,就可以通过参数化的方式简化测试用例的编号。
通过pytest.mark.parmtrize()
方法设置参数:
参数名:user,pw,expected
用来定义参数的名称
参数值:通过数组定义参数值时,每一个元组都是一条测试用例的测试数据
ids参数:默认none
用来重新定义测试用例的名称
python
import pytest
@pytest.mark.parametrize(
# 编写测试参数
"user,pw,expected",
[
("username", "password", "expected"),
("username02", "password2", "expected02")
],
# 测试用例名称
ids=["case1", "case2"]
)
接下来就是将原来的数据替换为自己的参数。
3.运行参数
-s
:打印信息
-v
:显示详细信息
-V
:显示版本信息
-k
:运行名称中包含某个字符串的测试用例
-q
:简化输出信息
-x
:测试用例失败,退出测试
使用示例(都是在控制台输入命令)
bash
# -s的使用
pytest -s
# -v的使用
pytest -v
# -V的使用
pytest -V
# -k的使用
pytest -k 方法名称 方法文件名
pytest -k 文件方法名
# -q的使用
pytest -q
#-x的使用
pytest -x 文件名
4.生成测试报告
4.1 使用命令生成Junit测试报告
bash
pytest filename.py --junit-xml=./directory/logname.xml
4.2 生成在线测试报告
bash
pytest filename.py --pastebin=all
点击链接访问效果
5.获取帮助
- 查看pytest版本
pytest --version
orpytest -V
1.显示可用的内置函数参数pytest --fixtures
我的电脑没有设置目录访问权限,如果需要使用帮助,建议使用以下两种方法。
2.获取帮助pytest --help
3.访问pytest
官方文档pytest documentation
6.控制用例的执行
在第N个测试用例执行失败后,结束测试用例执行
使用
pytest --maxfail=[失败次数] 文件名
python
# 执行测试用例时,失败两次后停止执行
pytest --maxfail=2 src/tests/test_mark.py
python
import pytest
# 失败用例1
def test_fails01():
assert 1 == 2
# 失败用例2
def test_fails02():
assert 1 == 2
# 成功用例
def test_success():
assert 1 == 1
7.多进程运行用例
安装pytest-xdist
使用如下命令:
bash
#安装
pip install pytest-xdist
#运行模式
pytest -n NUMCPUS
代码示例
python
import pytest
def test_case01():
assert 1 == 1
def test_case02():
assert 1 == 5 # 失败
def test_case03():
assert 1 == 1
def test_case04():
assert 1 == 3 # 失败
def test_case05():
assert 1 == 1
def test_case06():
assert 1 == 4 # 失败
还可以直接使用与九十九内核一样多的CPU将NUMCPUS修改为auto
,python会自动识别并执行。
8.通过标记表达式执行用例
bash
# 执行被装饰器修饰`@pytest.mark.slow`装饰的所有测试用例
python -m slow
不仅可以只选中他,也可以不选择。
使用
not
除它,or
两者其一,and
两者
bash
# 除了把slow标记的都执行
python -m not slow
# 只要被slow或者webtest标记就执行
python -m "slow or webtest"
# 只有方法被两个都标记才执行
python -m "slow and webtest"
可以选择添加pytest.ini配置文件用于介绍标记的含义。
ini
[pytest]
markers =
slow: mark tests as slow (deselect with '-m"not slow"')
webtest : mark tests as webtest
9.重新运行失败的用例
首先需要安装一个插件pytest-rerunfailures
bash
pip install pytest-rerunfailures
接着使用运行失败测试用例命令:
bash
#普通执行所有失败测试用例
pytest --reruns [执行次数] [文件目录]
#在两次重新执行前加延迟时间
pytest --reruns [执行次数] --reruns-deley [等待秒数] [文件目录]
10.setup和teardown函数
pytest 默认查找以 test_
开头的函数作为测试用例,并且使用 setup_function
和 teardown_function
(针对每个测试函数),或者 setup_module
和 teardown_module
(针对整个模块)作为测试的前置和后置操作。
python
import pytest
def multiply(a, b):
return a * b
"""
优先级
第一:setup_module/teardown_module 在当前文件在所有用例前执行与之后执行
第二:setup_function/teardown_function 在每个函数之前执行与之后执行
"""
def setup_module(module):
print("setup_module=================>")
def teardown_module(module):
print("teardown_module==============>")
def setup_function(module):
print("setup_function=================>")
def teardown_function(module):
print("teardown_function==============>")
def test_case01():
print("test_case01")
assert multiply(1, 2) == 2
def test_case02():
print("test_case02")
assert multiply(4, 6) == 24
在类中,你可以使用 pytest
的类级别的 setup 和 teardown 方法,即 setup_class
和 teardown_class
(注意,从 pytest 3.0 开始,推荐使用 setup_class
和 teardown_class
的新名称 setup_method
和 teardown_method
加上 @classmethod
装饰器来定义类级别的 setup 和 teardown,但更常见的是使用 @pytest.fixture(scope="class")
来定义类级别的 fixture,或者继续使用 setup_class
和 teardown_class
作为特殊方法名,但它们需要 @classmethod
装饰器)。
python
import pytest
def multiply(a, b):
return a * b
class TestMultiply:
@classmethod
def setup_class(cls):
print("setup_class---------->")
@classmethod
def teardown_class(cls):
print("teardown_class--------->")
def setup_method(self):
print("setup_method=======")
def teardown_method(self):
print("teardown_method=======")
def test_case01(self):
print("test_case01")
assert multiply(1, 2) == 2
def test_case02(self):
print("test_case02")
assert multiply(4, 6) == 24
上述代码中的 setup_class
和 teardown_class
方法并不是 pytest 的内置方法,它们只是遵循了一种常见的命名约定。pytest 实际上并不直接识别这些方法作为类级别的 setup 和 teardown。相反,你应该使用 pytest 的 fixture 功能,特别是设置 scope="class"
的 fixture,来实现类级别的 setup 和 teardown。
使用 fixture 的例子:
python
import pytest
@pytest.fixture(scope="class")
def class_setup(request):
print("setup class---------->")
# setup code here
request.cls.setup_attribute = "some value"
yield # yield 语句之后的代码会在 teardown 时执行
print("teardown class-------->")
class TestClass:
@pytest.mark.usefixtures("class_setup")
class TestMethods:
def test_method1(self):
print("running test_method1")
assert True
def test_method2(self):
print("running test_method2")
assert True
打印效果:
或者还可以使用更常见的做法是将 usefixtures 应用于类本身,或者将 fixture 应用于具体的测试方法。
下面的示例展示了更常见的用法:
python
@pytest.mark.usefixtures("class_setup")
class TestClass:
def test_method1(self):
print("running test_method1")
assert True
def test_method2(self):
print("running test_method2")
assert True
# 或者,直接在类定义中使用 autouse=True 的 fixture
@pytest.fixture(scope="class", autouse=True)
def class_setup_autouse(request):
print("setup class---------->")
# setup code here
yield
print("teardown class-------->")
class TestClass:
def test_method1(self):
print("running test_method1")
assert True
def test_method2(self):
print("running test_method2")
assert True
在这个修正后的示例中,class_setup_autouse fixture
会自动应用于 TestClass 中的所有测试方法,因为它被设置为 autouse=True
和 scope="class"
。这意味着它会在类中的所有测试方法之前执行一次 setup,在所有测试方法之后执行一次 teardown。