Pytest的setup和teardown

Pytest的setup和teardown

pytest实际上是python自带测试框架unittest的扩展,那么pytest是如何实现unittest中的setup和teardown的呢?

pytest初始化的类别和作用域

模块级别(Module level setup/teardown):作用于一个模块内的所有class和def,对于所有class和def,setup和teardown只执行一次

def setup_module(module):
""" setup any state specific to the execution of the given module."""
def teardown_module(module):
""" teardown any state that was previously setup with a setup_module
method.
"""

eg:

#!/usr/bin/env/python
# -*-coding:utf-8-*-

import pytest
"""
开始于模块始末,全局的
setup_module
teardown_module
"""

def setup_module():
    print "setup_module():在模块最之前执行\n"

def teardown_module():
    print "teardown_module:在模块之后执行"

def setup_function():
    print "setup_function():每个方法之前执行"

def teardown_function():
    print "teardown_function():每个方法之后执行\n"

def test_01():
    print "正在执行test1"
    x = "this"
    assert 'h' in x

def add(a,b):
    return a+b

def test_add():
    print "正在执行test_add()"
    assert add(3,4) == 7

运行结果:setup_module --> setup_function --> test_01--> teardown_function --> setup_function --> test_add()--> teardown_function --> teardown_module


类级别(Class level setup/teardown):作用于一个class内中的所有test,所有用例只执行一次setup,当所有用例执行完成后,才会执行teardown

@classmethod
def setup_class(cls):
""" setup any state specific to the execution of the given class (which
usually contains tests).
"""
@classmethod
def teardown_class(cls):
 """ teardown any state that was previously setup with a call to
setup_class.
"""

eg:

#!/usr/bin/env/python
# -*-coding:utf-8-*-

"""
在类之前和之后执行一次
setup_class
teardown_class
"""

import pytest

class TestClass(object):

    def setup_class(self):
        print "setup_class(self):每个类之前执行一次"

    def teardown_class(self):
        print "teardown_class(self):每个类之后执行一次"

    def add(self,a,b):
        print "这是加法运算"
        return a+b

    def test_01(self):
        print "正在执行test1"
        x = "this"
        assert 'h' in x

    def test_add(self):
        print "正在执行test_add()"
        assert self.add(3, 4) == 7

执行结果:
可以看出执行的顺序是 setup_class --》 test1 --》test_add()--》teardown_class


方法和函数级别(Method and function level setup/teardown):作用于单个测试用例,若用例没有执行(如被skip了)或失败了,则不会执行teardown

def setup_method(self, method):
""" setup any state tied to the execution of the given method in a
class. setup_method is invoked for every test method of a class.
"""
def teardown_method(self, method):
""" teardown any state that was previously setup with a setup_method
call.
"""

eg:

#!/usr/bin/env/python
# -*-coding:utf-8-*-

"""
开始于方法始末(在类中)
setup_method
teardown_method
"""
import pytest

class TestMethod(object):

    def setup_class(self):
        print "setup_class(self):每个类之前执行一次\n"

    def teardown_class(self):
        print "teardown_class(self):每个类之后执行一次"

    def setup_method(self):
        print "setup_method(self):在每个方法之前执行"

    def teardown_method(self):
        print "teardown_method(self):在每个方法之后执行\n"

    def add(self,a,b):
        print "这是加法运算"
        return a+b

    def test_01(self):
        print "正在执行test1"
        x = "this"
        assert 'h' in x

    def test_add(self):
        print "正在执行test_add()"
        assert self.add(3, 4) == 7

执行结果: setup_class --》 setup_method -->test1 -->teardown_method --》setup_method --> test_add()--》teardown_method --> teardown_class

若用例直接写在模块中,而不是在类中,则用:

def setup_function(function):
""" setup any state tied to the execution of the given function.
Invoked for every test function in the module.
"""
def teardown_function(function):
""" teardown any state that was previously setup with a setup_function
call.
"""

eg:

#!/usr/bin/env/python
# -*-coding:utf-8-*-
import pytest
"""
只对函数用例生效,不在类中
setup_function
teardown_function
"""

def setup_function():
    print "setup_function():每个方法之前执行"

def teardown_function():
    print "teardown_function():每个方法之后执行"

def test_01():
    print "正在执行test1"
    x = "this"
    assert 'h' in x

def test_02():
    print "正在执行test2"
    x = "hello"
    assert hasattr(x,"hello")

def add(a,b):
    return a+b

def test_add():
    print "正在执行test_add()"
    assert add(3,4) == 7

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

运行结果为:(-s为了显示用例的打印信息 -q只显示结果不显示过程)
可以看出执行的结果是:
setup_function--》 test_01 --》teardown_function
setup_function--》 test_02 --》teardown_function
setup_function--》 test_add --》teardown_function


当类和函数都有的时候

#!/usr/bin/env/python
# -*-coding:utf-8-*-

"""
在类之前和之后执行一次
setup_class
teardown_class
"""

import pytest

def setup_module():
    print "setup_module():在模块最之前执行\n"

def teardown_module():
    print "teardown_module:在模块之后执行"

def setup_function():
    print "setup_function():每个方法之前执行"

def teardown_function():
    print "teardown_function():每个方法之后执行\n"

def test_10():
    print "正在执行test1"
    x = "this"
    assert 'h' in x

def add0(a,b):
    return a+b

def test_add():
    print "正在执行test_add()"
    assert add0(3,4) == 7

class TestClass(object):

    def setup_class(self):
        print "setup_class(self):每个类之前执行一次"

    def teardown_class(self):
        print "teardown_class(self):每个类之后执行一次"

    def add(self,a,b):
        print "这是加法运算"
        return a+b

    def test_01(self):
        print "正在执行test1"
        x = "this"
        assert 'h' in x

    def test_add(self):
        print "正在执行test_add()"
        assert self.add(3, 4) == 7

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

运行结果:可以看出来,都互不影响,setup_module还是在最之前执行,所有之后执行。
setup_modele --> setup_function -->test1 -->teardown_function --> setuo_function -->test_add -->teardown_function -->setup_class -->teardown_class-->taerdown_module


pytest.fixture()装饰函数,结合yield实现初始化和teardown
举个例子(pytest)文档中的:

import smtplib
import pytest
@pytest.fixture(scope="module")
def smtp():
    smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
    yield smtp # provide the fixture value
    print("teardown smtp")
    smtp.close()

pytest.fixture采用yield实现setup和teardown操作,yield提供的参数为函数名称
与setup_module类似,pytest.fixture可作用于一个模块内的所有def和class。区别在于,必须将pytest.fixture()装饰的函数作为参数传递给用例。
pytest.fixture()装饰的函数必须作为参数传递给用例吗?

  1. 将class中的smtp_ini都删除,class中的用例执行失败,def用例执行成功;
  2. 将class中test_send_text的smtp_ini保留,其余2个删除,class中的用例都执行成功?这是为什么呢?只有1个用力传入了参数,但所有用例都执行成功了。
  3. 将class和def中的smtp_ini都删除,用例全部执行失败。

总结

4种方式的作用域:

  • setup_method:仅作用于class用例集中的用例,置于class内,每个用例都会调用一次
  • setup_function:作用于独立的def用例,不可作用于class内的用例
  • setup_class:作用于class用例集中的用例,置于class内,只在class用例执行的开始执行setup_class,结束时执行teardown_class
  • setup_module:作用于模块内的所有用例,置于class外,只在所以用例的开始执行setup_module,结束时执行teardown_module
  • pytest.fixture():作用于模块内的所有用例,但需要传递装饰函数为参数,可置于class内或class外
posted @ 2022-04-11 16:50  michaelchengjl  阅读(238)  评论(0编辑  收藏  举报