pytest 自动化框架

pytest

Pytest is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library.

1.1 pytest初识

pytest是一个非常成熟的全功能的Python测试框架,主要有以下几个特点
  • 简单灵活,容易上手
  • 支持参数化
  • 能够支持简单的单元测试和复杂的功能测试
  • pytest具有很多第三方插件,并且可以自定义扩展(pytest-selenium、pytest-html、pytest-rerunfailures、pytest-xdist、allure)
  • 测试用例的skip和xfail处理
  • 可以很好的和jenkins集成

1.2 pytest安装

pip install -U pytest
pytest --version # 会展示当前已安装版本

1.3 pytest约束

  • 所有的单测文件名都需要满足test_.py格式或_test.py格式
  • 在单测文件中,测试类以Test开头,并且不能带有 init 方法(注意:- 定义class时,需要以T开头,不然pytest是不会去运行该class的)
  • 在单测类中,可以包含一个或多个test_开头的函数。
  • 在执行pytest命令时,会自动从当前目录及子目录中寻找符合上述约束的测试函数来执行

1.4 pytest参数

  • -m : 标记markers用于标记测试 @pytest.mark.xxxx
  • -s : 标准输出,输出程序中 print
  • -k :筛选用例 使用表达式来指定希望运行的测试用例
  • -x :遇失败停止 测试在遇到第一次失败就停止
  • -q :输出简化的信息
  • -v :输出结果详细
  • -r :生成简略的指定需求的报告
  • -l :展示运行过程中的全局变量和局部变量

1.5 pytest setup、teardown

1.5.1 函数级别
  • 函数级的(setup_function、teardown_function)只对函数用例生效,而且不在类中使用
#!/usr/bin/env/python
# -*-coding:utf-8-*-

import pytest

def setup_function():
    print "每个方法之前执行"

def teardown_function():
    print "每个方法之后执行"

def add(a,b):
    return a+b

def test_add():
    print "正在执行"
    assert add(3,4) == 7

if __name__=="__main__":
    pytest.main(["-s","test_function.py"])
每个方法之前执行
正在执行
.每个方法之后执行
============================== 1 passed in 0.03s ==============================
1.5.2 类级别
  • 类级的(setup_class(self)、teardown_class(self) 只运行该类用例生效
#!/usr/bin/env/python
# -*-coding:utf-8-*-
import pytest

class TestClass(object):

    def setup_class(self):
        print ("每个类之前执行一次")

    def teardown_class(self):
        print ("每个类之后执行一次")

    def add(self,a,b):
        print ("这是加法运算")
        return a+b

    def test_add(self):
        print ("正在执行")
        assert self.add(3, 4) == 7

if __name__=="__main__":
    pytest.main(["-s","test_class.py"])
test_class.py 
每个类之前执行一次
正在执行
这是加法运算
.每个类之后执行一次


============================== 1 passed in 0.06s ==============================

1.6 pytest fixture

1.6.1 scope
  • fixture里面有个scope参数可以控制fixture的作用范围:
session>module>class>function
-function:每一个函数或方法都会调用

-class:每一个类调用一次,一个类中可以有多个方法

-module:每一个.py文件调用一次,该文件内又有多个function和class

-session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module
1.6.2 params
  • @pytest.fixture有一个params参数,接受一个列表,列表中每个数据都可以作为用例的输入
#!/usr/bin/env/python
# -*-coding:utf-8-*-
import pytest

@pytest.fixture(scope="module",params=["params1","params2","params3"])
def params(request):
    return request.param


def test_params(params):
    print(params)
    assert "params" in params

if __name__ == "__main__":
    pytest.main(["-s", "test_fixtrue.py"])
test_fixtrue.py::test_params[params1] params1
PASSED
test_fixtrue.py::test_params[params2] params2
PASSED
test_fixtrue.py::test_params[params3] params3
PASSED

============================== 3 passed in 0.06s ==============================
1.6.3 ids
  • 字符串id的列表,每个id对应于参数,是测试id的一部分,如果没有提供id,它们将从参数自动生成标识[测试用例编号]
#!/usr/bin/env/python
# -*-coding:utf-8-*-
import pytest

@pytest.fixture(scope="module",params=["params1","params2","params3"],ids=["num1","num2","num3"])
def params(request):
    return request.param


def test_params(params):
    print(params)
    assert "params" in params

if __name__ == "__main__":
    pytest.main(["-s", "test_fixtrue.py"])
test_fixtrue.py::test_params[num1] params1
PASSED
test_fixtrue.py::test_params[num2] params2
PASSED
test_fixtrue.py::test_params[num3] params3
PASSED

============================== 3 passed in 0.06s ==============================
1.6.4 autouse
  • True,则为所有测试激活fixture func可以看到它
  • False则显示需要参考来激活fixture
1.6.5 name
  • fixture的名称,这默认为装饰函数的名称。如果fixture在定义它的统一模块中使用,夹具的功能名称将被请求夹具的功能arg遮蔽,解决这个问题的一种方法时将装饰函数命令"fixture_“然后使用”@pytest.fixture(name=’’)"。

1.7 pytest 装饰器

1.7.1 pytest.mark.skip
  • 可以用于测试函数外,跳过该测试用例
@pytest.mark.skip(reason='Environment not supported')
def test():
    pass
1.7.2 pytest.mark.skipif
  • 可以用于测试函数外,有条件地跳过测试用例

@pytest.mark.skipif(condition='1<2',reason='Environment not supported')
def test():
    pass
1.7.3 pytest.skip()
  • 可以用于测试函数里,跳过测试用例
def test():
    if 1 < 2:
        pytest.skip('跳过该用例')
    pass
1.7.4 pytest.mark.xfail
  • 使用xfail标记测试用例预期失败,如果测试用例运行实际成功则显示XPASS,实际失败则显示XFAIL,xfail标记并不影响用例的运行
@pytest.mark.xfail(condition='1==1', reason="feature not implemented")
def test_1():
    pass
 
@pytest.mark.xfail(condition='1==1', reason="feature not implemented")
def test_2():
    assert 1 == 2

执行结果:
xfail_test.py::test_1 XPASS
xfail_test.py::test_2 XFAIL
1.7.5 pytest.mark.XXX
  • 自定义测试集
@pytest.mark.function
def test():
    pass

1.8 pytest 配置文件

1.8.1 pytest.ini
  • pytest.ini 可以修改 pytest 的默认行为,需要在项目内加载生效,pytest.ini 不能使用任何中文符号,包括汉字、空格、引号、冒号等
# pytest.ini
 
[pytest]

markers =
    demo : marks tests as demo
    smoke: marks tests as smoke
    test : marks tests as test   # mark标记


testpaths = test_path # 指定测试,目录

python_files =     test_*  *_test  check_*  # 修改测试用例发现规则
python_classes =   Test*   Check*
python_functions = test_*  check_*

log_cli = 1  # 控制台实施输出记录
 
addopts = -rsxX -l -strict --tb=short # 命令行参数设置为默认
1.8.2 conftest.py
  • 优点

    1、可以跨.py文件调用,有多个.py文件调用时,可让conftest.py只调用了一次fixture,或调用多次fixture

    2、conftest.py与运行的用例要在同一个pakage下,并且有__init__.py文件

    3、不需要import导入 conftest.py,pytest用例会自动识别该文件,放到项目的根目录下就可以全局目录调用了,如果放到某个package下,那就在改package内有效,可有多个conftest.py

    4、conftest.py配置脚本名称是固定的,不能改名称

    5、conftest.py文件不能被其他文件导入

    6、所有同目录测试文件运行前都会执行conftest.py文件

  • 应用场景

    1、每个接口需共用到的token

    2、每个接口需共用到的测试用例数据

    3、每个接口需共用到的配置信息

    4、常和 fixture 一起使用

1.9 pytest-html

1.9.1 安装
pip install pytest-html
1.9.2 命令
pytest --html=report.html   # 当前路径
pytest --html=./report/report.html  # 指定目录
pytest --html=report.html --self-contained-html  # 带CSS
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值