python的pytest框架

2020-01-14 21:12发布

pytest

1)简介

  • 官方文档地址:http://www.pytest.org/en/latest/getting-started.html
  • pytest中定义测试用例有三种方式:

  1)兼容unittest,已有的unittest库和文件都可以直接进行调用;

  2)可以基于简单的类进行定义,如果一个类里边没有初始化方法并且以test开头,系统便会认为这是一个测试用例(不需要继承,直接定义就行)

  3)可以直接定义测试函数来定义测试用例

2)安装:

  pip install pytest

3)修改配置:

  

例1:

import pytest

def func(x):
    return x + 1

def test_answer():
    assert func(3) == 5

if __name__ == "__main__":
    pytest.main()

 

例2:(修改运行方式后,编写代码生效)

import pytest

def func(x):
    return x + 1

def test_answer():
    assert func(3) == 5

class TestFunc:
    def test_answer(self):
        assert func(3) == 5


if __name__ == "__main__":
    pytest.main()

4)pytest的用例识别规则:

  用例识别:

  • Test* 类包含的所有的test_*方法
  • 不在class中的所有test_*函数
  • 类中不能初始化方法

  文件范围:

  • test_*.py
  • *_test.py

 5)用例执行顺序:

import pytest
def func(x):
    return x + 1
def test_answer():
    assert func(5) == 6
class TestFunc:
    @classmethod
    def setup_class(cls):
        print("setup_class")
    def setup(self):
        print("setup")
    def test_answer(self):
        assert func(5) == 6
    def test_demo(self):
        assert func(6) == 7
    def teardown(self):
        print("teardown")
    @classmethod
    def teardown_class(cls):
        print("teardown_class")

if __name__ == "__main__":
    pytest.main()

# 输出:

setup_class
setup
.teardown
setup
.teardown
teardown_class

setup_module: 整个类执行的时候执行

setup_function

pytest-order:调整执行的顺序

6)支持分组:(使用mark进行标记)

  • pytest.mark.webtest
  • pytest.mark.sec
  • Pytest -m "webtest and not sec"
import pytest

def func(x):
    return x + 1
class TestFunc:

    @classmethod
    def setup_class(cls):
        print("setup_class")

    def setup(self):
        print("setup")

    @pytest.mark.fail
    def test_answer(self):
        assert func(5) == 7

    @pytest.mark.success
    def test_demo(self):
        print("success")
        assert func(6) == 7

    def test_demo2(self):
        assert func(7) == 8

    def teardown(self):
        print("teardown")

    @classmethod
    def teardown_class(cls):
        print("teardown_class")

if __name__ == "__main__":
    pytest.main()

# 只运行成功的:
pytest -m "success"

7)fixture功能

简介:在测试函数的前后,由pytest执行的一个外壳函数,主要用来将测试前的准备、测试后的清理工作与核心代码进行分离;

【demo】   @pytest.fixture() 装饰器用于声明一个函数是fixture



import pytest

@pytest.fixture()
def some_data():
    return 42

def test_some_data(some_data):
    assert some_data == 42

fixture功能函数范围:


1> 放在单独的测试文件里;


2> 若需要多个测试文件共享fixture,可以放在某个公共目录下新建一个conftest,将fixture放在里面;


test_pytest2.py



def test_some_data(some_data):
    # assert some_data == 43
    print("3333333")

同一级目录下conftest.py



import pytest

@pytest.fixture()
def some_data():
    print("1111111")
    # return 42
    yield
    print("2222222")

3> 使用fixture传递接口数据;



import pytest

@pytest.fixture()
def a_list():
    return [1,2,3,24,5]

def test_a_list(a_list):
    assert a_list[2] == 3

4> fixture作用范围


fixture作用范围从大到小依次是:session>module>class>function

作用于function范围内的fixture:

import pytest
@pytest.fixture()
def first():
    print("\n获取用户名")
    a = 'TEST'
    return a

@pytest.fixture(scope="function")
def second():
    print("\n获取密码")
    b = "123456"
    return b

def test_1(first):
    "用例传fixture"
    print("测试账号:%s" % first)
    assert first == "TEST"

def test_2(second):
    "用例传fixture"
    print("测试密码:%s" % second)
    assert second == "123456"

# 运行结果

SETUP F first
test_pytest2.py::test_1 (fixtures used: first).
TEARDOWN F first
SETUP F second
test_pytest2.py::test_2 (fixtures used: second).
TEARDOWN F second

 

用这个命令可以看到具体的执行顺序:pytest --setup-show test_pytest2.py

作用于class范围内的fixture:

import pytest

@pytest.fixture(scope="class")
def first():
    print("\n获取用户名,scop为class级别只运行一次")
    a = "TEST"
    return a

class TestCase():
    def test_1(self,first):
        "用例传fixture"
        print("测试账号:%s" % first)
        assert first == "TEST"

    def test_2(self,first):
        "用例传fixture"
        print("测试账号:%s" % first)
        assert first == "TEST"


# 输出:

SETUP C first
test_pytest2.py::TestCase::test_1 (fixtures used: first).
test_pytest2.py::TestCase::test_2 (fixtures used: first).
TEARDOWN C first

作用于module范围内的fixture:

import pytest

@pytest.fixture(scope="module")
def first():
    print("\n获取用户名,scop为module级别只运行一次")
    a = "TEST"
    return a

def test_1(first):
    "用例传fixture"
    print("测试账号:%s" % first)
    assert first == "TEST"

class TestCase():
    def test_2(self,first):
        "用例传fixture"
        print("测试账号:%s" % first)
        assert first == "TEST"

# 输出:
 SETUP    M first
      test_pytest2.py::test_1 (fixtures used: first).
      test_pytest2.py::TestCase::test_2 (fixtures used: first).
 TEARDOWN M first

作用于session范围内的fixture: 多个文件调用一次,可以跨.py文件,每个py文件是一个module;

[conftest.py]

import pytest

@pytest.fixture(scope="session")
def first():
    print("\n获取用户名,scop为module级别只运行一次")
    a = "TEST"
    return a

[test_pytest2.py]

def test_1(first):
    "用例传fixture"
    print("测试账号:%s" % first)
    assert first == "TEST"

[demo.py]

def test_2(first):
    "用例传fixture"
    print("测试账号:%s" % first)
    assert first == "TEST"

运行:

pytest --setup-show test_pytest2.py demo.py

输出:

SETUP S first
test_pytest2.py::test_1 (fixtures used: first).
demo.py
demo.py::test_2 (fixtures used: first).
TEARDOWN S first

4> fixture参数化

    .pytest.fixture():在fixture级别的function处参数化

import pytest
import requests

par_to_test = [{
    "case":"serach a word:haha",
    "headers":{},
    "querystring":{
        "wd":"hh"
    },
    "payload":{},
    "expected":{
        "status_code":200
    }
},
{
    "case":"serach a word2:kuku",
    "headers":{},
    "querystring":{
        "wd":"kuku"
    },
    "payload":{},
    "expected":{
        "status_code":200
    }
    }
]

@pytest.fixture(params=par_to_test)
def class_scope(request):
    print(request.param)
    return request.param

def test_baidu_search(class_scope):
    url = "http://www.baidu.com"
    r = requests.request("GET",url,data=class_scope["payload"],
                         headers=class_scope["headers"],
                         params=class_scope["querystring"])
    assert r.status_code == class_scope["expected"]["status_code"]

   @pytest.mark.parametrize:允许在function或class级别的参数化,为特定的测试函数或类提供多个argument/fixture设置

    @pytest.mark.success
    @pytest.mark.parametrize("input,expect",
                             [(5, 6),
                              (7, 8),
                              (2, 2)
                              ])
    def test_demo(self, input, expect):
        print("success")
        assert func(input) == expect

 .pytest_generate_tests:实现自定义动态参数化或扩展

  略

 

8)配置文件:

pytest的非测试文件主要有以下几种:

1> pytest.ini  : pytest的主要测试文件,可以改变pytest的默认行为,有很多可配置项;

 设置默认按照python -v xx.py   的方式运行:

所以allure所需要的报告数据会放置在allure-results文件夹下,执行  allure generate allure-results -o allure,生成报告放在当前目录的allure文件夹下;

为了放置拼写错误,可以再pytest.ini中注册标记:     --strict 是一个注册标记,若是运行一个没有注册的marker就会报错

 

 

检查是否标记成功: pytest --markers

指定pytest的运行最低版本:若是本地安装低于指定版本,运行报错:

 

 

指定pytest忽略某些目录,pytest在执行的时候会递归遍历所有的子目录,包括一些没有必要遍历的目录,可以在pytest.ini中指定忽略,进而缩小pytest的搜索范围;

 

 

指定访问目录

 

 

 避免文件名冲突

在每一个文件夹下增加__init.py__文件

 

2> conftest.py :  本地的插件库,其中hook函数和fixture作用于conftest.py文件所在的目录及所有子目录;

3> __init__.py : 每个测试子目录都包含此文件时,那么在多个测试目录中可以出现同名文件;

 

9)运行

  • 设置第N个失败后停止运行:
pytest --maxfail=2 # stop after two failures
  • 指定运行类下的某个方法
pytest test_pytest2.py::TestClass::test_one
  • 指定运行某个方法,py文件中没有类
pytest test_pytest2.py::test_one
  • 运行case名字中包含“baidu”的case,使用 -k 来过滤case;
pytest -v -k "baidu" test_pytest2.py

  效果:

 

  • 通过标记表达式运行:见6:

pytest -v -m "success" test_pytest2.py

  • 展示在给定配置下,哪些case会被运行  --collect-only:
pytest -v -k "baidu" --collect-only test_pytest2.py
  • 运行打印详细信息:
pytest -v test_pytest2.py

  效果:

  • 以安静的报告模式执行测试功能
pytest -q test_sysexit.py

输出:

1 passed in 0.12s

 

10)报告生成:

生成xml风格的报告:

pytest --junitxml=report.xml

生成兼容Junit风格的报告:

JUnit风格的xml报告:

pytest--junitxml = path

下载:

pip install pytest-html

 

生成HTML风格的报告:

1)pytest-html报告:

pytest--html = report.html

  下载:

pip install pytest-html

  执行:cd到用例的目录执行:pytest --html=report.html

 

 

allure2报告:

pytest--alluredir = /tmp/my_allure_results

安装pytest: pip install pytest

安装allure2:  从这个地址  http://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/  下载最新的安装包,解压到python目录下,进入bin目录,配置系统环境变量;

检查:allure --version

运行case:

pytest test_pytest1.py --alluredir allure-report

生成报告:

allure serve allure-report

 

 

 

*** 若有疑问,欢迎讨论,QQ群号:744419090 ***

标签: