<返回更多

pytest 前后置操作详谈

2023-04-18  微信公众号  测试玩家勇哥
加入收藏

pytest 的前置与后置处理

Pytest贴心的提供了类似setup、teardown的方法,并且还超过四个,一共有十种

setup和teardown的详细使用

代码

#!/usr/bin/env Python/ target=_blank class=infotextkey>Python# -*- coding: utf-8 -*-import pytest

def setup_module():    print("=====整个.py模块开始前只执行一次:登录=====")
def teardown_module():    print("=====整个.py模块结束后只执行一次:数据清理=====")
def setup_function():    print("===每个函数级别用例开始前都执行setup_function===")
def teardown_function():    print("===每个函数级别用例结束后都执行teardown_function====")
def test_one():    print("1")
def test_two():    print("2")
class TestCase():    def setup_class(self):        print("====整个测试类开始前只执行一次setup_class====")
    def teardown_class(self):        print("====整个测试类结束后只执行一次teardown_class====")
    def setup_method(self):        print("==测试类里面每个用例执行前都会执行setup_method==")
    def teardown_method(self):        print("==测试类里面每个用例结束后都会执行teardown_method==")
    def setup(self):        print("=测试类里面每个用例执行前都会执行setup=")
    def teardown(self):        print("=测试类里面每个用例结束后都会执行teardown=")
    def test_three(self):        print("3")
    def test_four(self):        print("4")

if __name__ == '__mAIn__':    pytest.main(["-q", "-s", "-ra", "testc.py"])    

运行结果

C:Userschenyongzhi11.virtualenvsapi-test-project-FfYYNBU1Scriptspython.exe D:/apk_api/api-test-project/debug/debug_pytest.py =====整个.py模块开始前只执行一次:登录========每个函数级别用例开始前都执行setup_function===1.===每个函数级别用例结束后都执行teardown_function=======每个函数级别用例开始前都执行setup_function===2.===每个函数级别用例结束后都执行teardown_function========整个测试类开始前只执行一次setup_class======测试类里面每个用例执行前都会执行setup_method==3.==测试类里面每个用例结束后都会执行teardown_method====测试类里面每个用例执行前都会执行setup_method==4.==测试类里面每个用例结束后都会执行teardown_method======整个测试类结束后只执行一次teardown_class=========整个.py模块结束后只执行一次:数据清理=====
4 passed in 0.33s
进程已结束,退出代码0

 

 

fixture的详细使用

fixture的优势

fixture参数列表

@pytest.fixture(scope="function", params=None, autouse=False, ids=None, name=None)def test():    print("fixture初始化的参数列表")

参数列表

注意

session的作用域:是整个测试会话,即开始执行pytest到结束测试

测试用例调用fixture的方式

  1. 将fixture名称作为测试用例函数的输入参数

  2. 测试用例加上装饰器:@pytest.mark.usefixtures(fixture_name)

  3. fixture设置autouse=True

    1. 将fixture名称作为测试用例函数的输入参数

import pytest

# 调用方式一@pytest.fixturedef login():    print("输入账号,密码先登录")

def test_s1(login):    print("用例 1:登录之后其它动作 111")

def test_s2():  # 不传 login    print("用例 2:不需要登录,操作 222")

if __name__ == '__main__':    pytest.main(["-s", 'debug_pytest.py'])

结果

============================= test session starts =============================platform win32 -- Python 3.9.5, pytest-7.3.1, pluggy-1.0.0rootdir: D:apk_apiapi-test-projectdebugplugins: Faker-18.4.0collected 2 items
debug_pytest.py 输入账号,密码先登录用例 1:登录之后其它动作 111.用例 2:不需要登录,操作 222.
============================== 2 passed in 0.14s ==============================
进程已结束,退出代码0

方式2:测试用例加上装饰器:@pytest.mark.usefixtures(fixture_name)

import pytest

# 调用方式一@pytest.fixturedef login():    print("输入账号,密码先登录")

# 调用方式二@pytest.fixturedef login2():    print("please输入账号,密码先登录")

@pytest.mark.usefixtures("login2", "login")def test_s11():    print("用例 11:登录之后其它动作 111")

输出:

============================= test session starts =============================collecting ... collected 1 item
teat_learn03.py::test_s11 please输入账号,密码先登录输入账号,密码先登录PASSED                                         [100%]用例 11:登录之后其它动作 111
============================== 1 passed in 0.01s ==============================
Process finished with exit code 0

注意:

fixture的实例化顺序
import pytest
order = []

@pytest.fixture(scope="session")def s1():    order.Append("s1")

@pytest.fixture(scope="module")def m1():    order.append("m1")

@pytest.fixturedef f1(f3, a1):    # 先实例化f3, 再实例化a1, 最后实例化f1    order.append("f1")    assert f3 == 123

@pytest.fixturedef f3():    order.append("f3")    a = 123    yield a

@pytest.fixturedef a1():    order.append("a1")

@pytest.fixturedef f2():    order.append("f2")

def test_order(f1, m1, f2, s1):    # m1、s1在f1后,但因为scope范围大,所以会优先实例化    assert order == ["s1", "m1", "f3", "a1", "f1", "f2"]

执行结果:断言成功

关于fixture的注意点

添加了 @pytest.fixture ,如果fixture还想依赖其他fixture,需要用函数传参的方式,不能用 @pytest.mark.usefixtures() 的方式,否则会不生效

@pytest.fixture(scope="session")def open():    print("===打开浏览器===")
@pytest.fixture# @pytest.mark.usefixtures("open") 不可取!!!不生效!!!def login(open):    # 方法级别前置操作setup    print(f"输入账号,密码先登录{open}")

fixture的后置teardown

用fixture实现teardown并不是一个独立的函数,而是用 yield 关键字来开启teardown操作(yield 之前是前置,之后是后置)

import pytest


@pytest.fixture(scope="session")
def open():
    # 会话前置操作setup
    print("===打开浏览器===")
    test = "测试变量是否返回"
    yield test
    # 会话后置操作teardown
    print("==关闭浏览器==")


@pytest.fixture
def login(open):
    # 方法级别前置操作setup
    print(f"输入账号,密码先登录---{open}")
    name = "==我是账号=="
    pwd = "==我是密码=="
    age = "==我是年龄=="
    # 返回变量
    yield name, pwd, age
    # 方法级别后置操作teardown
    print("登录成功")


def test_s2(login):
    print("==用例2==")
    print(login)

 

输出:

============================= test session starts =============================
collecting ... collected 1 item

test_05.py::test_s2 ===打开浏览器===
输入账号,密码先登录---测试变量是否返回
PASSED                                               [100%]==用例2==
('==我是账号==', '==我是密码==', '==我是年龄==')
登录成功
==关闭浏览器==

============================== 1 passed in 0.01s ==============================

 

yield注意事项

addfinalizer

在用法上,addfinalizer跟yield是不同的,需要你去注册作为终结器使用的函数。

import pytest


@pytest.fixture()
def demo_fixture(request):
    print("n这个fixture在每个case前执行一次")

    def demo_finalizer():
        print("n在每个case完成后执行的teardown")

    # 注册demo_finalizer为终结函数
    request.addfinalizer(demo_finalizer)


def test_01(demo_fixture):
    print("n===执行了case: test_01===")


def test_02(demo_fixture):
    print("n===执行了case: test_02===")


def test_03(demo_fixture):
    print("n===执行了case: test_03===")

 

输出:

============================= test session starts =============================
collecting ... collected 3 items

test_06.py::test_01 
这个fixture在每个case前执行一次
PASSED                                               [ 33%]
===执行了case: test_01===

在每个case完成后执行的teardown

test_06.py::test_02 
这个fixture在每个case前执行一次
PASSED                                               [ 66%]
===执行了case: test_02===

在每个case完成后执行的teardown

test_06.py::test_03 
这个fixture在每个case前执行一次
PASSED                                               [100%]
===执行了case: test_03===

在每个case完成后执行的teardown


============================== 3 passed in 0.04s ==============================

Process finished with exit code 0

 

yield与addfinalizer的区别

1. addfinalizer可以注册多个终结函数。
import pytest

import pytest


@pytest.fixture()
def demo_fixture(request):
    print("n这个fixture在每个case前执行一次")

    def demo_finalizer():
        print("n在每个case完成后执行的teardown")

    def demo_finalizer2():
        print("n在每个case完成后执行的teardown2")

    def demo_finalizer3():
        print("n在每个case完成后执行的teardown3")

    # 注册demo_finalizer为终结函数
    request.addfinalizer(demo_finalizer)
    request.addfinalizer(demo_finalizer2)
    request.addfinalizer(demo_finalizer3)


def test_01(demo_fixture):
    print("n===执行了case: test_01===")


def test_02(demo_fixture):
    print("n===执行了case: test_02===")


def test_03(demo_fixture):
    print("n===执行了case: test_03===")

 

输出:

============================= test session starts =============================
collecting ... collected 3 items

test_06.py::test_01 
这个fixture在每个case前执行一次
PASSED                                               [ 33%]
===执行了case: test_01===

在每个case完成后执行的teardown3

在每个case完成后执行的teardown2

在每个case完成后执行的teardown

test_06.py::test_02 
这个fixture在每个case前执行一次
PASSED                                               [ 66%]
===执行了case: test_02===

在每个case完成后执行的teardown3

在每个case完成后执行的teardown2

在每个case完成后执行的teardown

test_06.py::test_03 
这个fixture在每个case前执行一次
PASSED                                               [100%]
===执行了case: test_03===

在每个case完成后执行的teardown3

在每个case完成后执行的teardown2

在每个case完成后执行的teardown


============================== 3 passed in 0.04s ==============================

Process finished with exit code 0

 

可以看到,注册的3个函数都被执行了,但是要注意的是执行顺序,与注册的顺序相反

2. 当setUp的代码执行错误,addfinalizer依旧会执行

conftest.py的详细讲解

可以理解成一个专门存放fixture的配置文件,如果多个测试用例文件(test_*.py)的所有用例都需要用登录功能来作为前置操作,那就不能把登录功能写到某个用例文件中去了,conftest.py的出现,就是为了解决上述问题,单独管理一些全局的fixture。

conftest.py配置fixture注意事项

conftest.py使用举例

conftest.py文件(scope=“session”)

import pytest


@pytest.fixture(scope="session")
def login():
    print("输入账号密码")
    yield
    print("清理数据完成")

 

case文件:

import pytest


class TestLogin1():
    def test_1(self, login):
        print("用例1")

    def test_2(self):
        print("用例2")

    def test_3(self, login):
        print("用例3")


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

输出:

输入账号密码
PASSED                                  [ 33%]用例1
PASSED                                  [ 66%]用例2
PASSED                                  [100%]用例3
清理数据完成

 

可以看出,conftest.py内的fixture方法的作用范围是session,调用时,整个.py文件只会调用一次

conftest.py注意事项

关键词:pytest      点击(1)
声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多pytest相关>>>