• pytest-fixtured


    fixture的作用

    1.同unittest的setup和teardown,作为测试前后的初始化设置。

    fixture的使用

    1.作为前置条件使用

    2.fixture的的作用范围

    1.作为前置条件使用

    @pytest.fixture()
    def a():
        return 3
    
    def test_b(a):
        assert a==3

    2.fixture的作用范围

    首先实例化更高范围的fixture.默认为scope="function",每个测试函数都会执行一次。

    • session : 多个.py文件执行时,只调用一次
    • module: 每一个.py调用一次
    • class : 每个类调用一次
    • function: 每个函数调用一次

    3.fixture 作为setup/teardown执行

    yield 前的在测试之前执行,yield后的在测试完后执行

    @pytest.fixture
    def a():
        print("setup")
        yield
        print("teardown")
    
    def test_b(a):
        print("测试")

    4.fixture with

    # @pytest.fixture()
    # def write_file():
    #     f = open("myfile.txt","w")
    #     f.write("hello")
    #     yield
    #     f.close()
    @pytest.fixture()
    def write_file():
        with open("myfile.txt","w") as f:
            f.write("hello1")
    
    def test_write_file(write_file):
        print("ceshi")

    5. fixture request可以请求测试的上下文

    @pytest.fixture(params=[1,3])
    def a(request):
        return request.param
    
    def test_b(a):
        assert a in [1,3]

    6.fixture 工厂模式

    在单个测试中,如果想多次调用该fixture,就可以用工厂模式。fixture的结果返回的不是数据,而是返回生成数据的函数。

    @pytest.fixture
    def make_customer_record():
        def _make_customer_record(name):
            return {"name": name, "orders": []}
    
        return _make_customer_record
    
    
    def test_customer_records(make_customer_record):
        customer_1 = make_customer_record("Lisa")
        customer_2 = make_customer_record("Mike")
        customer_3 = make_customer_record("Meredith")

    7.带参数的fixture

    params列表有几个值,测试就会执行几次。例params=[1,2],测试用例会执行2次

    @pytest.fixture(params=[0, 1, pytest.param(2, marks=pytest.mark.skip)])
    def data_set(request):
        return request.param
    
    
    def test_data(data_set):
        assert data_set in [0,1]

    8. 模块化:在一个fixtrue调用另一个fixture

    fixture a可以调用另一个fixture c

    @pytest.fixture()
    def c():
        print("c")
    
    @pytest.fixture()
    def a(c):
        print("a")
    
    def test_b(a):
        pass

    9.通过fixture 对测试用例进行分组

    pytest在测试运行期间最大程度地减少了fixture的数量。如果有参数化的fixtrue,那么使用它的所有测试将首先使用一个实例执行,然后在创建下一个fixture实例之前调用终结器。除其他外,这简化了对创建和使用全局状态的应用程序的测试。

    
    
    @pytest.fixture(scope="module", params=[1, 2])
    def input_x(request):
    print("setup")
    param = request.param
    yield param
    print("teardown")

    def
    test_a(input_x): print("test_a") assert input_x in [1,2] def test_b(input_x): print("test_b") assert input_x in [1,2] if __name__ == '__main__': pytest.main(['-q','fixture_1.py']) 运行结果 fixture_1.py setup .test_a .test_b teardown setup .test_a .test_b teardown

    如上所示,设置scope='module',会将所有调用该fixture的用例都执行一遍,而fixture只执行了一次。

     10.使用类、模块、项目中的fixture

    userfixtures,可以调用在其他模块定义好的fixture.

    @pytest.mark.usefixtures("x")
    class TestCase:
    
        def test_1(self):
            print("test_1")
    
        def test_2(self):
            print("test_2")
    
    
    if __name__ == '__main__':
        pytest.main(['-q','test_2.py'])

    a.usefixture,可以添加多个fixture

    @pytest.mark.usefixtures("a", "b")
    def test():
        pass

    b.可以使用标记机制的通用功能在测试模块级别指定fixture

    pytestmark = pytest.mark.usefixtures("a")
    
    def test_a():
    
    def test_b():

    c.可以将项目中所有测试所需的fixture放入ini文件中

    #pytest.ini
    
    [pytest]
    usefixtures = x
    
    #test_case.py
    @pytest.mark.usefixtures
    def test_a():
        pass

    11.自动使用fixture

    autouse=True  

    有时你可能希望自动调用fixture, 而无需显示声明函数参数或usefixtures装饰器。

    import pytest
    
    
    class DB:
        def __init__(self):
            self.intransaction = []
    
        def begin(self, name):
            self.intransaction.append(name)
    
        def rollback(self):
            self.intransaction.pop()
    
    
    @pytest.fixture(scope="module")
    def db():
        return DB()
    
    
    class TestClass:
        @pytest.fixture(autouse=True)
        def transact(self, request, db):
            db.begin(request.function.__name__)
            yield
            db.rollback()
    
        def test_method1(self, db):
            assert db.intransaction == ["test_method1"]
    
        def test_method2(self, db):
            assert db.intransaction == ["test_method2"]

    类级transact夹具标记有autouse = true ,这意味着该类中的所有测试方法都将使用此夹具,而无需在测试函数签名或类级usefixtures修饰器中声明它。

    • autouse固定装置遵循scope=关键字参数:如果有autouse固定装置,scope='session'则无论定义在何处,都只能运行一次。scope='class'表示它将每节课运行一次,依此类推。
    • 如果在测试模块中定义了自动使用夹具,则其所有测试功能都会自动使用它。
    • 如果在conftest.py文件中定义了自动使用的固定装置,则其目录下所有测试模块中的所有测试都将调用固定装置。
    • 最后,请谨慎使用:如果您在插件中定义了自动使用夹具,它将在安装该插件的所有项目中的所有测试中调用它。如果固定装置仅在某些设置下(例如在ini文件中)仍然可以工作,则这很有用。这样的全局夹具应始终快速确定它是否应该做任何工作,并避免其他昂贵的导入或计算。

    请注意,上面的transact灯具很可能是您希望在项目中不启用的灯具。做到这一点的规范方法是将事务处理定义放入conftest.py文件中,而无需使用autouse

    # content of conftest.py
    @pytest.fixture
    def transact(request, db):
        db.begin()
        yield
        db.rollback()

    然后例如通过声明需要让TestClass使用它:

    @pytest.mark.usefixtures("transact")
    class TestClass:
        def test_method1(self):
            ...

    该TestClass中的所有测试方法都将使用事务处理夹具,而模块中的其他测试类或功能将不使用它,除非它们也添加了transact引用。

    fixture覆盖

    1.对于测试文件夹级别,具有相同名称的fixture可以被覆盖

    tests/
        __init__.py
    
        conftest.py
            # content of tests/conftest.py
            import pytest
    
            @pytest.fixture
            def username():
                return 'username'
    
        test_something.py
            # content of tests/test_something.py
            def test_username(username):
                assert username == 'username'
    
        subfolder/
            __init__.py
    
            conftest.py
                # content of tests/subfolder/conftest.py
                import pytest
    
                @pytest.fixture
                def username(username):
                    return 'overridden-' + username
    
            test_something.py
                # content of tests/subfolder/test_something.py
                def test_username(username):
                    assert username == 'overridden-username'

    2.在测试模块中覆盖fixture

    tests/
        __init__.py
    
        conftest.py
            # content of tests/conftest.py
            import pytest
    
            @pytest.fixture
            def username():
                return 'username'
    
        test_something.py
            # content of tests/test_something.py
            import pytest
    
            @pytest.fixture
            def username(username):
                return 'overridden-' + username
    
            def test_username(username):
                assert username == 'overridden-username'
    
        test_something_else.py
            # content of tests/test_something_else.py
            import pytest
    
            @pytest.fixture
            def username(username):
                return 'overridden-else-' + username
    
            def test_username(username):
                assert username == 'overridden-else-username'

    3.在文件内覆盖

    tests/
        __init__.py
    
        conftest.py
            # content of tests/conftest.py
            import pytest
    
            @pytest.fixture
            def username():
                return 'username'
    
            @pytest.fixture
            def other_username(username):
                return 'other-' + username
    
        test_something.py
            # content of tests/test_something.py
            import pytest
    
            @pytest.mark.parametrize('username', ['directly-overridden-username'])
            def test_username(username):
                assert username == 'directly-overridden-username'
    
            @pytest.mark.parametrize('username', ['directly-overridden-username-other'])
            def test_username_other(other_username):
                assert other_username == 'other-directly-overridden-username-other'

    4.对于某些测试模块,参数化的夹具被非参数化的版本覆盖,而非参数化的夹具被参数化的版本覆盖。显然,测试文件夹级别也是如此。

    tests/
        __init__.py
    
        conftest.py
            # content of tests/conftest.py
            import pytest
    
            @pytest.fixture(params=['one', 'two', 'three'])
            def parametrized_username(request):
                return request.param
    
            @pytest.fixture
            def non_parametrized_username(request):
                return 'username'
    
        test_something.py
            # content of tests/test_something.py
            import pytest
    
            @pytest.fixture
            def parametrized_username():
                return 'overridden-username'
    
            @pytest.fixture(params=['one', 'two', 'three'])
            def non_parametrized_username(request):
                return request.param
    
            def test_username(parametrized_username):
                assert parametrized_username == 'overridden-username'
    
            def test_parametrized_username(non_parametrized_username):
                assert non_parametrized_username in ['one', 'two', 'three']
    
        test_something_else.py
            # content of tests/test_something_else.py
            def test_username(parametrized_username):
                assert parametrized_username in ['one', 'two', 'three']
    
            def test_username(non_parametrized_username):
                assert non_parametrized_username == 'username'

    实用技巧

    1.conftest.py 共享fixture。如果定义fixture过多且需要多个地方调用,可将fixture放入conftest.py文件中,使用时不需要导入

  • 相关阅读:
    python中单例模式
    python中常用的内置方法
    面向对象之反射
    绑定方法与非绑定方法
    python多态与抽象类
    python的组合与封装
    面向对象之继承与派生
    面向对象之类与对象
    python模块与包
    数据结构与算法_语言和框架特性前瞻和bug修复
  • 原文地址:https://www.cnblogs.com/jiablogs/p/12024255.html
Copyright © 2020-2023  润新知