Pytest - setup、teardown、fixture的详细使用
一、setup、teardown使用案例
1、代码
''' @Date:2022/2/13 13:02 @Author:一加一 ''' 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("one") def test_two(): print("two") 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("three") def test_four(self): print("four") if __name__ == '__main__': pytest.main(["-q", "-s", "-ra", "setup_test.py"])
2、执行结果
二、fixture的优势
- 命名方式灵活,不局限于 setup 和teardown 这几个命名
- conftest.py 配置里可以实现数据共享,不需要 import 就能自动找到fixture
- scope="module" 可以实现多个.py 跨文件共享前置
- scope="session" 以实现多个.py 跨文件使用一个 session 来完成多个用例
三、Fixture参数列表
@pytest.fixture(scope="function", params=None, autouse=False, ids=None, name=None) def test(): print("fixture初始化的参数列表")
- scope:可以理解成fixture的作用域,默认:function,还有class、module、package、session四个【常用】
- autouse:默认:False,需要用例手动调用该fixture;如果是True,所有作用域内的测试用例都会自动调用该fixture
- name:默认:装饰器的名称,同一模块的fixture相互调用建议写个不同的name
注意 session的作用域:是整个测试会话,即开始执行pytest到结束测试
四、Fixture的三种调用方法
1、方式一:函数或类里面方法直接传fixture的函数参数名称
定义fixture跟定义普通函数差不多,唯一区别就是在函数上加个装饰器@pytest.fixture(),fixture命名不要以test开头,跟用例区分开。
fixture是有返回值的,没有返回值默认为None。
用例调用fixture的返回值,直接就是把fixture的函数名称当做变量名称。
import pytest @pytest.fixture() def test1(): a = "南京" return a def test2(test1): assert test1 == "南京" if __name__ == '__main__': pytest.main("-s fixture_test.py")
2、方式二:使用装饰器@pytest.mark.usefixtures()修饰需要运行的用例
import pytest @pytest.fixture() def test1(): a = "南京" print("fixture") return a def test2(test1): assert test1 == "南京" @pytest.fixture() def login(): print("请先登录") @pytest.mark.usefixtures("login","test1") def test3(): print("用例1:调用fixture") @pytest.mark.usefixtures("login") @pytest.mark.usefixtures("test1") def test4(): ''' 叠加usefixtures:如果一个方法或者一个class用例想要同时调用多个fixture, 可以使用@pytest.mark.usefixture()进行叠加。 注意叠加顺序,先执行的放底层,后执行的放上层。 :return: ''' print("用例2:叠加userfixture") if __name__ == '__main__': pytest.main("-s fixture_test.py")
注意:usefixtures与传fixture区别
如果fixture有返回值,那么usefixture就无法获取到返回值,这个是装饰器usefixture与用例直接传fixture参数的区别。
当fixture需要用到return出来的参数时,只能讲参数名称直接当参数传入,不需要用到return出来的参数时,两种方式都可以。
3、方式三:fixture自动使用autouse=True
当用例很多的时候,每次都传这个参数,会很麻烦。fixture里面有个参数autouse,默认是False没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了,autouse设置为True,自动调用fixture功能
import pytest @pytest.fixture(autouse=True) def login3(): print("====auto===,自动执行该fixture") def test5(): print("用例3:执行前自动执行fixture") if __name__ == '__main__': pytest.main("-s fixture_test.py")
4、知识点
- 在类声明上面加 @pytest.mark.usefixtures() ,代表这个类里面所有测试用例都会调用该fixture
- 可以叠加多个 @pytest.mark.usefixtures() ,先执行的放底层,后执行的放上层
- 可以传多个fixture参数,先执行的放前面,后执行的放后面
- 如果fixture有返回值,用 @pytest.mark.usefixtures() 是无法获取到返回值的,必须用传参的方式(方式一)
- 添加了 @pytest.fixture ,如果fixture还想依赖其他fixture,需要用函数传参的方式,不能用 @pytest.mark.usefixtures() 的方式,否则会不生效
五、Fixture之yield实现teardown
前面讲的,其实都是setup的操作,那么现在就来讲下teardown是怎么实现的
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_s1(login): print("==用例1==") # 返回的是一个元组 print(login) # 分别赋值给不同变量 name, pwd, age = login print(name, pwd, age) assert "账号" in name assert "密码" in pwd assert "年龄" in age def test_s2(login): print("==用例2==") print(login) if __name__ == '__main__': pytest.main("-s fixture_test.py")
六、Conftest.py的使用
1、什么是conftest.py
可以理解成一个专门存放fixture的配置文件
2、实际开发场景
多个测试用例文件(test_*.py)的所有用例都需要用登录功能来作为前置操作,那就不能把登录功能写到某个用例文件中去了
3、如何解决上述场景问题?
conftest.py的出现,就是为了解决上述问题,单独管理一些全局的fixture
4、conftest.py配置fixture注意事项
- pytest会默认读取conftest.py里面的所有fixture
- conftest.py 文件名称是固定的,不能改动
- conftest.py只对同一个package下的所有测试用例生效
- 不同目录可以有自己的conftest.py,一个项目中可以有多个conftest.py
- 测试用例文件中不需要手动import conftest.py,pytest会自动查找
5、实例
参考博客:https://www.cnblogs.com/poloyy/p/12663601.html
1)目录结构
2)HttprunnerProject目录下
conftest.py代码
最顶层的conftest,一般写全局的fixture,在Web UI自动化中,可能会初始化driver
import pytest '''最顶层的conftest,一般写全局的fixture,在Web UI自动化中,可能会初始化driver''' @pytest.fixture(scope="session") def login(): print("====登录功能,返回账号,token===") name="test" token="123bfdaj" yield name,token #如果有返回值,可以在yield后面直接写返回值就好了,如果有多个直接用(返回值1,返回值2) print("====退出登录!!!====") @pytest.fixture(autouse=True) def get_info(login): name,token=login print(f"== 每个用例都调用的外层fixture:打印用户token: {token} ==")
test_conftest.py代码
同级目录下的测试用例
'''跟最顶层的conftest目录下的测试用例''' import pytest def test_get_info(login): name,token = login print("***基础用例:获取用户个人信息***") print(f"用户名:{name}, token:{token}")
执行结果
3)baidu目录下
conftest.py代码
配置一些针对baidu这个网站的测试用例独有的fixture,譬如:打开baidu网站
'''baidu目录下的conftest.py,配置一些针对baidu这个网站的测试用例独有的fixture,譬如:打开baidu网站''' import pytest @pytest.fixture(scope="module") def open_baidu(login): name,token=login print(f"###用户 {name} 打开baidu网站###")
test_baidu_conftest.py
某个功能模块下的测试用例
'''某个功能模块下的测试用例''' def test_case01(open_baidu): print("正确打开百度搜索")
执行结果