第五:Pytest-yield操作(自定义测试用例的预置条件-后置--类似teardown)
一.简介1.上一篇中实现在每个用例之前执行初始化操作那么用例执行完后如需要清除数据等操作使用yield来实现1.1.fixture通过scope参数控制setup级别既然有setup作为用例前的操作用例执行完后那肯定也有teardown操作1.2.这里用到fixture的teardown操作并不是独立的函数用yield关键字呼唤teardown操作2.之前学习的都是测试用例的前置固件也就是相当于setup2.1.那有没有什么方式可以表示出teardown”用yield和addfinalizer方式来表示importpytest# 声明前置scopemodule# pytest.fixture表示声明的固件pytest.fixture(scopemodule)deflogin():print(\n【前置】登录博客园)# 后置yieldprint(\n【后置】退出博客园)deftest_1(login):print(测试用例1,登录博客园之后发布随笔111)deftest_2():print(测试用例2,不需要登录博客园浏览文章222)deftest_3(login):print(测试用例3,登录博客园之后删除随笔333)if__name____main__:pytest.main([-s,test_bjhg_class1.py])二.yield介绍1.yield是个关键字它不是单独存在的要写在fixtrue标记的固件中2.在声明的固件myfixture中加入yield关键字在它下面写测试用例执行后想要运行的代码其他有关于固件的使用没有任何差别2.1.需要说明的一点是在pytest主函数中增加了一个参数–setup-show他会显示出固件的执行情况3.fixture里面的teardown用yield来唤醒teardown的执行3.1.如果测试用例中的代码出现异常或者断言失败并不会影响他的固件中yield后的代码执行3.1.1.但是如果固件中的yield之前的代码也就是相当于setup部分的代码出现错误或断言失败3.1.2.那么yield后的代码将不会再执行当然测试用例中的代码也不会执行3.2.也可以通过request.addfinalizer()的方式实现teardown3.3.在固件中传入request参数又在固件中定义了一个内置函数最后将定义的内置函数添加到request的addfinalizer中三.scope“function”函数级别中yieId–没有类1.当pytest.fixture(scopefunction)时Pytest的yieId类似Unittest的teartown1.1.yieId在每个方法函数都会执行一次2.test_bjhg_function1.pyimportpytest pytest.fixture(scopefunction)def login(): print(登录成功)yield print(用例执行完成收尾)def test1(login): print(操作1)print(-----------------------------------------------)def test2(login): print(操作2)print(-----------------------------------------------)def test3(login): print(操作3)print(-----------------------------------------------)if__name____main__:pytest.main([-s,test_bjhg_function1.py])2.1.运行结果虽然test1test2test3都调用login函数但是它会在每一个用例前执行一次3.如果test1不调用test2(调用login)test3不调用运行顺序会是怎样的importpytest pytest.fixture(scopefunction)def login(): print(登录成功)yield print(用例执行完成收尾)def test1(): print(操作1)print(-----------------------------------------------)def test2(login): print(操作2)print(-----------------------------------------------)def test3(): print(操作3)print(-----------------------------------------------)if__name____main__:pytest.main([-s,test_bjhg_function1.py])3.1.运行结果function级别的fixture在当前.py模块里只会在用例(test2)第一次调用前执行一次四.scope“module”模块级别中yieId–没有类1.fixture参数scopemodule”module作用是整个.py文件都会生效(整个文件只会执行一次)用例调用时参数写上函数名称就行importpytest pytest.fixture(scopemodule)def login(): print(登录成功)yield print(用例执行完成收尾)def test1(login): print(操作1)print(-----------------------------------------------)def test2(login): print(操作2)print(-----------------------------------------------)def test3(login): print(操作3)print(-----------------------------------------------)if__name____main__:pytest.main([-s,test_bjhg_function1.py])1.1.运行结果虽然test1test2test3都调用login函数但是它只会在第一个用例前执行一次2.如果test1不调用test2(调用login)test3不调用运行顺序会是怎样的importpytest pytest.fixture(scopemodule)def login(): print(登录成功)yield print(用例执行完成收尾)def test1(): print(操作1)print(-----------------------------------------------)def test2(login): print(操作2)print(-----------------------------------------------)def test3(): print(操作3)print(-----------------------------------------------)if__name____main__:pytest.main([-s,test_bjhg_function1.py])2.1.运行结果module级别的fixture在当前.py模块里只会在用例(test2)第一次调用前执行一次五.scope“class”类级别中yieId–有类1.fixture参数scopeclass”class作用是整个类都会生效(整个类只会执行一次)用例调用时参数写上函数名称就行importpytestclassTestClass:pytest.fixture(scopeclass)deflogin(self):print(登录成功)yieldprint(用例执行完成收尾)deftest1(self,login):print(操作1)print(-----------------------------------------------)deftest2(self,login):print(操作2)print(-----------------------------------------------)deftest3(self,login):print(操作3)print(-----------------------------------------------)if__name____main__:pytest.main([-s,test_bjhg_function1.py])2.运行结果虽然test1test2test3都调用login函数但是它只会在第一个用例前执行一次3.如果test1不调用test2(调用login)test3不调用运行顺序会是怎样的importpytestclassTestClass:pytest.fixture(scopeclass)deflogin(self):print(登录成功)yieldprint(用例执行完成收尾)deftest1(self):print(操作1)print(-----------------------------------------------)deftest2(self,login):print(操作2)print(-----------------------------------------------)deftest3(self):print(操作3)print(-----------------------------------------------)if__name____main__:pytest.main([-s,test_bjhg_function1.py])3.1.运行结果class级别的fixture在当前文件里只会在用例(test2)第一次调用前执行一次六.yield执行teardowna.前边的代码中有一个yield关键字其实就是用来唤醒teardown1.fixture里面的teardown用yield来唤醒teardown的执行importpytest pytest.fixture(scopemodule)def login(): print(登录成功)yield print(执行teardown!)print(用例执行完成收尾)def test1(login): print(操作1)print(-----------------------------------------------)def test2(login): print(操作2)print(-----------------------------------------------)def test3(login): print(操作3)print(-----------------------------------------------)if__name____main__:pytest.main([-s,test_bjhg_function1.py])1.1.运行结果七.yield遇到异常1.如果其中一个用例出现异常不影响yield后面的teardown执行运行结果互不影响并且在用例全部执行完后会呼唤teardown的内容importpytest pytest.fixture(scopemodule)def login(): print(登录成功)yield print(执行teardown!)print(用例执行完成收尾)def test1(login): print(操作1)print(-----------------------------------------------)# 如果第一个用例异常了不影响其他的用例执行raise NameError# 模拟异常def test2(login): print(操作2)print(-----------------------------------------------)def test3(login): print(操作3)print(-----------------------------------------------)if__name____main__:pytest.main([-s,test_bjhg_function1.py])1.1.运行结果2.如果在前置setup就异常了那么是不会去执行yield后面的teardown内容importpytestpytest.fixture(scopemodule)deflogin():print( 开始执行setup前置登录 )# 前置步骤直接抛出异常raiseException(登录接口调用失败前置报错)yieldprint(执行teardown!)print(用例执行完成收尾)deftest1(login):print(操作1)deftest2(login):print(操作2)deftest3(login):print(操作3)if__name____main__:pytest.main([-s,test_bjhg_function1.py])3.yield也可以配合with语句使用3.1.test_yield2.pyimportsmtplibimportpytest pytest.fixture(scopemodule)def smtp(): with smtplib.SMTP(smtp.gmail.com)as smtp: yield smtp# provide the fixture value# 新增测试用例函数必须 test_ 开头接收 fixture 参数def test_send_email(smtp): print(SMTP 连接对象正常可用, smtp)if__name____main__:pytest.main([-s, __file__])八.addfinalizer终结函数1.除yield可以实现teardown在request-context对象中注册addfinalizer方法也可以实现终结函数1.1.conftest.pyimportsmtplibimportpytest pytest.fixture(scopemodule)def smtp_connection(request): smtp_connectionsmtplib.SMTP(smtp.gmail.com,587,timeout5)def fin(): print(teardown smtp_connection)smtp_connection.close()request.addfinalizer(fin)returnsmtp_connection# provide the fixture value2.yield和addfinalizer方法都是在测试完成后呼叫相应的代码3.但是addfinalizer不同的是可以注册多个终结函数4.这些终结方法总是会被执行无论在之前的setup有没有抛出错误4.1.这个方法对于正确关闭所有的fixture创建的资源非常便利即使其一在创建或获取时失败