pytest 和 unittest
pytest 功能更强;unittest 优势是python内置
pytest兼容unittest,如果之前的用例是 unittest 编写的,可以使用 pytest 直接运行。
pytest 特有的运行用例的功能,都可以使用
- 直接使用 python 关键字 assert 断言,不需要记住 self.assert* 等各种各样的断言方式。
- 失败用例提供非常详细的错误信息。
- 自动发现和收集测试模块和用例。
- 非常灵活的 fixture 管理
- mark 用例标记机制
- 和 unittest 和 nose 兼容
- python3.6+ 和 pypy3 兼容
- 丰富的插件系统。
pytest 的用例规则:
1,模块名称 test_*.py 或者 *_test.py
2, 测试用例函数的名称 def test_ () 函数名以test_开头
3, 可以不定义测试类,定义类的名以Test开头,里面的函数名以test_开头;类里不可以使用__init__
pytest用例的运行顺序:
1、用例文件按照文件名ASCII进行排序
2、用例文件内用例按照上下先后顺序执行
安装pytest pip install pytest
并设置默认的运行器为 pytest
生成测试报告,先安装插件
- pip install pytest-html
- pytest --html=报告名称.html
unittestreports风格的报告,安装插件(自动生成时间戳)
- pip install pytest-testreport
- pytest --report=报告名称.html
以上两种风格的报告同时存在会出现不兼容情况
pytest三种运行方式:
1, 播放键
2, 命令行 pytest --html=output.html 当使用 pytest 找不到命令,可以换成 python -m pytest
3, python 模块运行 pytest.main(['--html=output.html'])
'-s'显示用例执行的输出内容(print),在启动文件使用
'-v'显示执行的进度,百分比
用例筛选的流程
1,需要在 pytest.ini 中注册标记的名称
2,在测试用例函数或者测试用例类上面加上 @pytest.mark.标记名;可以同时加多个筛选时满足一个即可
3, 运行指定标签 pytest -m "标签名"
4,如果运行多个标签, and or
5, 使用标签时记得用双引号把标签名称括起来
如何实现实现数据驱动
第一种方式:使用 unittest 风格的 ddt
第二种方式:pytest 自己的 ddt, 叫做参数化, @pytest.mark.parametrize('case_info', [])
测试用例方法中用个形参来接收数据,形参名字必须与参数化的'case_info'一致。
注意事项:pytest 的数据驱动/参数化不能和 unittest 兼容,如果使用/继承了 unittest.TestCase
就不能用 pytest 的ddt了。
夹具可以调用夹具,和调用po的方法
# pytest夹具
# 测试用例以函数形式写,夹具使用setup_function()和teardown_function();
# 夹具名字固定,有多少个函数执行多少次夹具
def setup_function():
print('前置')
def teardown_function():
print('后置')
def test_fixture():
assert 1==2
def test_fixture2():
assert 1==1
class TestFixture():
# 测试用例以类的形式写,类夹具使用setup_class(cls)和teardown_class(cls);
# 夹具名字固定,类里只执行一次类夹具
@classmethod
def setup_class(cls):
print('类前置')
@classmethod
def teardown_class(cls):
print('类后置')
# 测试用例以类的形式写,在类里面函数夹具使用setup_method(self)和teardown_method(self);
# 夹具名字固定,类里面有多少个函数执行多少次夹具
def setup_method(self):
print('里前置')
def teardown_method(self):
print('里后置')
def test_fixture(self):
assert 1 == 2
def test_fixture2(self):
assert 1 == 1
# module级别的夹具,该模块执行一次;
# 还有session(流程/会话级别), package(包) 级别的夹具
def setup_module():
print("module 级别的 setup")
def teardown_module():
print("module 级别的 teardown")
不是写在 conftest 文件文件的夹具,不导入的话只在当前文件内使用;
如果夹具名字有重复,后面的会覆盖前面的。
conftest 文件
# 实际应用过程中会在项目根目录下创建一个 conftest.py 文件,存放pytest所有的夹具;
# 可在该项目中直接使用夹具,无需导入
# @pytest.fixture 声明这是一个测试夹具
# @pytest.fixture(scope='function', autouse=True) 可使用scope='function', autouse=True参数控制
# scope='function' 限制作用范围,默认是函数,范围包括function,class,module,package,session
# autouse=True 根据作用范围自动调用,不传不调用
import pytest
@pytest.fixture(scope='function')
def login():
print('登录前置')
# yield 之前的为前置
yield
# yield 之后的为后置
print('登录后置')
@pytest.fixture(scope='class')
def token():
print('类前置')
yield
print('类后置')
@pytest.fixture(scope='module')
def connect_to_module():
print("前置条件:模块级别...")
yield
print("后置清理:模块级别...")
@pytest.fixture(scope='package')
def connect_to_package():
print("包(目录):包级别...")
yield
print("后置清理:包级别...")
@pytest.fixture(scope='session', autouse=True)
def connect_to_session():
print("前置:session级别...")
yield
print("后置清理:session级别...")
用例py文件使用夹具
import pytest
# 写在项目根目录 conftest.py 文件中的夹具可以在该项目中直接拿来使用,无需导入
# 如果该夹具在声明时没有使用scope限制级别,则默认是函数级别的夹具 @pytest.fixture(scope='function')
# @pytest.mark.usefixtures('login','token','connect_to_module') 可使用多个夹具,根据夹具作用范围使用先后顺序
# 没有设置自动使用夹具时,夹具作用范围为调用处开始,根据作用范围结束。
# 如module自调用处开始使用前置(如果是函数则函数处调用;如果是在类里面的某个函数处调用则从执行到该函数时开始),文件结束使用后置
@pytest.mark.usefixtures('login') # 该函数使用夹具
def test_fixture():
assert 1==2
@pytest.mark.usefixtures('login','token','connect_to_module') # 类前置也可以在此处使用
def test_fixture2():
assert 1==1
# @pytest.mark.usefixtures('login') # 这个类下的每个函数都使用夹具
@pytest.mark.usefixtures('login','token','connect_to_package','connect_to_session') # 这个类下的每个函数都使用login夹具,使用一次token类夹具
class TestFixture(): # 不能在类名后面的括号中使用夹具,语法错误
# @pytest.mark.usefixtures('login') # 这个函数使用夹具
def test_fixture(self):
assert 1 == 2
# @pytest.mark.usefixtures('token') # 也可以在此处使用类夹具,该类执行前后执行一次类夹具
def test_fixture2(self):
assert 1 == 1
# 夹具中yield类似函数中的return,可以把后面测试用例中需要用到的夹具中的数值返回出来
# 如果有多个值,则以元组形式返回
@pytest.fixture(scope='function')
def login_token():
token = 1 + 1
headers = 2 + 2
yield token, headers, 'daxigua'
print('后置清理')
# @pytest.mark.usefixtures("fixture_name", "fixture_name_2") 只适用于不需要获取夹具的返回值这种场景
# 如果夹具的返回值需要在测试用例当中使用, 通过在测试用例方法后面加上参数,参数名称和夹具名称同名
# 夹具中的
def test_fixture():
assert 1 == 2
def test_fixture2(login_token):
print(login_token)
assert 2 == login_token[0]
class TestFixture():
def test_fixture(self):
assert 1 == 2
def test_fixture2(self):
assert 1 == 1
allure
1, 下载 allure-commandline (GitHub - allure-framework/allure2: Allure Framework is a flexible lightweight multi-language test reporting tool. It provides clear graphical reports and allows everyone involved in the development process extract maximum of information from everyday testing process. , 解压即可;在bin目录下运行cmd allure;如果全局需要配置环境变量)
2, pip install allure-pytest
3, 生成 allure 测试报告, pytest --alluredir=output (=前后不能有空格,生成json文件到该文件夹下)
4, allure serve output (查看报告,会搭建服务,以网页形式打开;在jenkins中安装对应插件即可查看,无需启动服务)