pytest框架中前置和后置的学习总结:1、setup和teardown的使用2、confest.py文件中fixture的使用

一、概述

介绍pytest框架中的前置和后置之前,先来介绍一个测试场景,比如我们要测试淘宝的购物车的添加功能,那我们是不是需要先登录,然后再到购物车模块去操作,最后是退出账号,那么像这种测试一个模块前后需要做的准备工作和收尾的工作,可以通过写代码实现,但是pytest帮我们提供了两种方法:
1、通过teardown和setup来控制前置和后置执行的位置。
2、通过在conftest.py文件中利用在函数上加@pytest.fixture()装饰器的方法来实现。
作用范围区别:
1是仅在当前的所在的模块中生效。
2是可以在多个.py文件中共享,或者是多个包以及整个测试项目下被共享。

二、通过setup_xx 和 teardown_xx来实现前置和后置

根据用例运行级别可以分为以下几种
模块级(setup_module/teardown_module)开始于模块始末,全局的

函数级(setup_function/teardown_function)只对函数用例生效(不在类中)

类级(setup_class/teardown_class)只在类中前后运行一次(在类中)

方法级(setup_method/teardown_method)开始于方法始末(在类中)

类里面的(setup/teardown)运行在调用方法的前后
举例说明:
一、函数级别的。

import pytest
count = 1

def setup_function():
    print("函数测试开始了.....")

def teardown_function():
    print("函数测试结束了.....")

def add(x, y):
    if type(x) is int or type(y) is int:
        return x+y
    else:
        raise TypeError
# @pytest.mark.ToDo3

def test_case1():
    print("正常值。。。")
    assert add(1,2) == 3

# @pytest.mark.toDo2
# @pytest.mark.skipif(count <= 1, reason = "count值太小")
def test_case2():
    print("异常值")
    with pytest.raises(TypeError):
        assert add(1,"2") != 3

if __name__ == '__main__':
    pytest.main(['-sq',  'test_10_21.py'])

运行结果,可以看到:每个测试函数执行前和执行后都会去执行一遍。

C:\Python36\python.exe D:/自动化B/python_test/test_10_21.py
函数测试开始了.....
正常值。。。
.函数测试结束了.....
函数测试开始了.....
异常值
.函数测试结束了.....
sss
2 passed, 3 skipped in 0.04s

Process finished with exit code 0

二、模块级别的。
将上面的那两行代码改成下面两行:

def setup_module():
    print("模块测试开始了.....")

def teardown_module():
    print("模块测试结束了.....")

运行结果:

函数测试开始了.....
正常值。。。
.异常值
.sss函数测试结束了.....

2 passed, 3 skipped in 0.06s

可以看到,在整个模块运行前和运行结束后分别执行了一次。

三、类和方法(这里需要注意一下,这个是放在类中的。)

import pytest
count = 1
def setup_module():
    print("模块测试开始了.....")

def teardown_module():
    print("模块测试结束了.....")
    
def add(x, y):
    if type(x) is int or type(y) is int:
        return x+y
    else:
        raise TypeError
# @pytest.mark.ToDo3

def test_case1():
    print("正常值。。。")
    assert add(1,2) == 3

# @pytest.mark.toDo2
# @pytest.mark.skipif(count <= 1, reason = "count值太小")
def test_case2():
    print("异常值")
    with pytest.raises(TypeError):
        assert add(1,"2") != 3
# @pytest.mark.skip(reason = "我不想被执行")
class TestCase(object):
    def setup_class(self):
        print("类测试开始了.....")

    def teardown_class(self):
        print("类测试结束了.....")

    def setup_method(self):
        print("方法测试开始了.....")

    def teardown_method(self):
        print("方法测试结束了.....")

    def setup(self):
        print("方法调用测试开始了.....")

    def teardown(self):
        print("方法调用测试结束了.....")
    def test_CASE3(self):
        print("特殊字符:")
        with pytest.raises(TypeError):
            assert add("$", "****") != 3

@pytest.mark.skip()
def test_error():
    print("这是一个错误结果的用例测试")
    assert 1 == 2
@pytest.mark.skip()
def test_CASE4():
    print("特殊字符:")
    with pytest.raises(TypeError):
        assert add("][]", ">?>") != 3


if __name__ == '__main__':
    pytest.main(['-sv',  'test_10_21.py'])

运行结果:

模块测试开始了.....
正常值。。。
.异常值
.类测试开始了.....
方法测试开始了.....
方法调用测试开始了.....
特殊字符:
.方法调用测试结束了.....
方法测试结束了.....
类测试结束了.....
ss模块测试结束了.....

3 passed, 2 skipped in 0.07s

三、通过conftest.py文件中添加@pytest.fixture的方式

首先介绍下conftest,py文件吧,conftest.py文件名是固定的命名方式,不可改变,位置可以放在根目录下,也可以放在模块下,放在不同的位置,则在执行测试用例的时候被执行的顺序也是不一样的。放在根目录下,则会在首次执行根目录下的setup.py的时候会被执行一次。然后接着去执行包下的conftest.py(前提是包下面放了conftest.py)
从上面看,正式因为conftest。py文件只要有,每次执行用例的时候会自动加载这个文件,那么是不是跟前置和后置有点像,所以就有人想到了在这个文件中放置@pytest.fixture,通过scope来控制作用的范围:

@pytest.fixture(scope=“function”, params=None, autouse=False, ids=None, name=None)

 1. scope参数:
scope:有四个级别参数 "function" (默认), "class", "module" or "session"
scope参数为session,那么所有的测试文件执行前执行一次
scope参数为module,那么每一个测试文件执行前都会执行一次
scope参数为class,那么每一个测试文件中的测试类执行前都会执行一次
scope参数为function,那么每一个测试文件中的每一个测试用例执行前都会执行一次
 2. params参数:
默认是None,也可以传参数,传多个值时,则会执行多次测试用例,这样就实现了参数化。
@pytest.fixture(scope="function",params=[1,2])
def data(request):
	return request.param
def test_add(data):#会被执行两次,第一次传入的data=1,第二次传入的data=2
	assert 1==data
 3. autouse参数
 默认是False,只有传入参数名称才会被调用,当开启时,则不管有没有将函数作为参数传入到测试用例中,都会被执行。
 ids和name很少用,这里不重点介绍了。。。感兴趣可以自行查找相关资料了解。。

使用的方法是在测试用例的类上通过@pytest.mark.usefixture()
或者直接在方法的参数中出传入被@pytest.fixture()装饰的函数名即可。

以上介绍的都是fixture实现前置,那么后置怎么实现呢?
接下来介绍一下yeild关键字,这个应该学过python的都不陌生了吧,生成器中就是使用的这个关键字来实现的,感兴趣的小伙伴可以去查看我这篇文章中有介绍:https://blog.csdn.net/weixin_43726471/article/details/120600966
那yield和return有什么区别呢?

@pytest.fixture(scope="function")
def yied_ex():
	print("前置工作") #step1
	yield "run...." #step2
	print("后置工作")#step4

def test_yield(yied_ex):
	print("返回什么{}".format(yied_ex))#step3

运行结果:

test0205.py::test_yield 前置工作
返回什么run....
PASSED后置工作

相同点:
yield和return都是作为函数的返回
区别:
return返回,函数就结束了,并且return后面不能跟代码了,否则会报语法错误。
但是yield后面还是可以跟代码,遇到yield就停止了,返回yield后的数据,然后回到函数调用的地方,执行完之后,会再次回到yield这里,继续执行yield后面的语句。

四、总结

为什么有setup和teardown,还要出现fixture?
像如下这种场景,就比较适合用fixture,setup和teardown无法满足。
一个.py文件中,有三个测试用例,其中测试用例1和测试用例3需要获得登陆的token,测试用例2不需要,那么可以在测试用例1和测试用例3中传入函数名,2不用传,则不会被执行。

@pytest.fixture(scope="function")
def login():
	return "token"

def test_01(login):
	print("返回什么{}".format(login))

def test_02():
	assert 1==1

def test_03(login):
	print("返回什么{}".format(login))

运行结果:

test0205.py::test_01 返回什么token
PASSED
test0205.py::test_02 PASSED
test0205.py::test_03 返回什么token
PASSED

如果使用setup来实现的话:

def setup_function():
	print("前置准备。。。")
def test_01():
	# print("返回什么{}".format(login))
	pass

def test_02():
	assert 1==1

def test_03():
	# print("返回什么{}".format(login))
	pass

返回结果:

test0205.py::test_01 前置准备。。。
PASSED
test0205.py::test_02 前置准备。。。
PASSED
test0205.py::test_03 前置准备。。。
PASSED

可以看到全部被执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
pytest ,可以使用装饰器 `@pytest.fixture` 来定义测试用例的前置后置操作。 前置操作需要在测试用例执行前完成,可以使用 `@pytest.fixture(scope="function")` 来定义作用域为函数级别的前置操作。例如: ```python import pytest @pytest.fixture(scope="function") def setup(): print("\nsetup") def test_case1(setup): print("test_case1") def test_case2(setup): print("test_case2") ``` 在这个例子,`setup` 函数被定义为函数级别的前置操作,即每个测试用例执行前都会执行一次。`test_case1` 和 `test_case2` 都有一个参数 `setup`,这个参数是用来调用 `setup` 函数的。 后置操作需要在测试用例执行后完成,可以使用 `yield` 和 `addfinalizer` 来定义作用域为函数级别的后置操作。例如: ```python import pytest @pytest.fixture(scope="function") def setup(): print("\nsetup") yield print("\nteardown") def test_case1(setup): print("test_case1") def test_case2(setup): print("test_case2") ``` 在这个例子,`setup` 函数被定义为函数级别的前置后置操作,即每个测试用例执行前都会执行一次,执行完测试用例后也会执行一次。`yield` 前面的代码是前置操作,`yield` 后面的代码是后置操作。通过 `yield` 可以将控制权交给测试用例执行,测试用例执行完后再执行后置操作。如果需要在测试用例执行后执行多个后置操作,可以使用 `addfinalizer`,例如: ```python import pytest @pytest.fixture(scope="function") def setup(request): print("\nsetup") def teardown(): print("\nteardown1") request.addfinalizer(teardown) def teardown2(): print("\nteardown2") request.addfinalizer(teardown2) def test_case1(setup): print("test_case1") def test_case2(setup): print("test_case2") ``` 在这个例子,定义了两个后置操作 `teardown1` 和 `teardown2`,它们都会在测试用例执行完后执行。可以使用 `request.addfinalizer` 将这些后置操作添加到 `request` 对象,这样它们就会按照添加的顺序执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

如梦@_@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值