微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐