• python之pytest_addoption : 命令行参数


    场景
    1.一般公司测试环境都有多套,测试的时候我们需要在不同的环境下进行
    2.在自动化执行时,在不同的环境下我们要指定不同的系统配置,每次修改框架代码配置这个很不自动化
    3.pytest_addoption注册参数 这个就很好的解决了这个问题,它能在执行命令的时候传递参数

    二、@pytest.fixture()函数的介绍

    2.1 pytest.fixture()函数介绍

    fixture是pytest的核心功能,也是亮点功能;

     fixture的目的是提供一个固定基线,在该基线上测试可以可靠地和重复地执行。fixture提供了区别于传统单元测试(setup/teardown)有显著改进:

    (1)有独立的命名,并通过声明它们从测试函数、模块、类或整个项目中的使用来激活;

    (2)按模块化的方式实现,每个fixture都可以相互调用;

    (3)fixture的范围从简单的单元扩展到复杂的功能测试,允许根据配置和组件选项对fixture和测试用例进行参数化,或者跨函数function,类class,模块module或整个测试会话session范围。

    Fixture参数详解及使用

    @pytest.fixture(scope = "function",params=None,autouse=False,ids=None,name=None)
    参数详解:
    1、SCOPE
    用于控制Fixture的作用范围
    作用类似于Pytest的setup/teardown
    默认取值为function(函数级别),控制范围的排序为:session > module > class > function
    取值范围 说明
    function 函数级 每一个函数或方法都会调用
    class 函数级 模块级 每一个.py文件调用一次
    module 模块级 每一个.py文件调用一次
    session 会话级 每次会话只需要运行一次,会话内所有方法及类,模块都共享这个方法
     

      

    作用范围举例:
    
    scope = “function”
    语法:
    
    @pytest.fixture() #或者 @pytest.fixture(scope='function')
    

      场景一:做为参数传入

    import pytest
    # fixture函数(类中) 作为多个参数传入
    @pytest.fixture()
    def login():
        print("打开浏览器")
        a = "account"
        return a
        
    @pytest.fixture()
    def logout():
        print("关闭浏览器")
    
    class TestLogin:
        #传入lonin fixture
        def test_001(self, login):
            print("001传入了loging fixture")
            assert login == "account"
    
        #传入logout fixture
        def test_002(self, logout):
            print("002传入了logout fixture")
    
        def test_003(self, login, logout):
            print("003传入了两个fixture")
    
        def test_004(self):
            print("004未传入仍何fixture哦")
    
    if __name__ == '__main__':
        pytest.main()
    

      运行pytest命令结果如下:

    ============================= test session starts =============================
    platform win32 -- Python 3.7.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: E:\FYR\python\111
    plugins: html-3.1.1, metadata-1.11.0collected 4 items
    
    test_fixture1.py                                                     [100%]
    
    ============================== 4 passed in 0.03s ==============================11打开浏览器
    .001传入了loging fixture
    关闭浏览器
    .002传入了logout fixture
    11打开浏览器
    关闭浏览器
    .003传入了两个fixture
    .004未传入仍何fixture哦
    
    Process finished with exit code 0
    

      场景二、Fixture的相互调用

    import pytest
    # fixtrue作为参数,互相调用传入
    @pytest.fixture()
    def account():
        a = "account"
        print("第一层fixture")
        return a
        
    #Fixture的相互调用一定是要在测试类里调用这层fixture才会生次,普通函数单独调用是不生效的
    @pytest.fixture()   
    def login(account):
        print("第二层fixture")
    
    class TestLogin:
        def test_1(self, login):
            print("直接使用第二层fixture,返回值为{}".format(login))
    
        def test_2(self, account):
            print("只调用account fixture,返回值为{}".format(account))
    
    
    if __name__ == '__main__':
        pytest.main()
    

     

    ============================= test session starts =============================
    platform win32 -- Python 3.7.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: E:\FYR\python\111
    plugins: html-3.1.1, metadata-1.11.0collected 2 items
    
    test_fixture1.py                                                       [100%]
    
    ============================== 2 passed in 0.03s ==============================第一层fixture
    第二层fixture
    .直接使用第二层fixture,返回值为None
    第一层fixture
    .只调用account fixture,返回值为account
    
    Process finished with exit code 0
    

      2.scope = “class”:【@pytest.fixture(scope='class')

     *当测试类内的每一个测试方法都调用了fixture,fixture只在该class下所有测试用例执行前执行一次

    **测试类下面只有一些测试方法使用了fixture函数名,这样的话,fixture只在该class下第一个使用fixture函数的测试用例位置开始算,后面所有的测试用例执行前只执行一次。而该位置之前的测试用例就不管。
    语法

    场景一、

    import pytest
    
    
    # fixture作用域 scope = 'class'
    @pytest.fixture(scope='class')
    def login():
        print("scope为class")
    
    
    class TestLogin:
        def test_1(self, login):
            print("用例1")
    
        def test_2(self, login):
            print("用例2")
    
        def test_3(self, login):
            print("用例3")
    
    
    if __name__ == '__main__':
        pytest.main()
    

      结果

    ============================== 3 passed in 0.03s ==============================scope为class
    .用例1
    .用例2
    .用例3
    
    Process finished with exit code 0
    

      场景二、

    import pytest
    
    
    @pytest.fixture(scope='class')
    def login():
        a = '123'
        print("输入账号密码登陆")
    
    
    class TestLogin:
        def test_1(self):
            print("用例1")
    
        def test_2(self):
            print("用例2")
    
        def test_3(self, login):
            print("用例3")
    
        def test_4(self):
            print("用例4")
    
    
    if __name__ == '__main__':
        pytest.main()
    

      结果

    ============================= test session starts =============================
    platform win32 -- Python 3.7.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: E:\FYR\python\111
    plugins: html-3.1.1, metadata-1.11.0collected 4 items
    
    test_fixture1.py .用例1
    .用例2
    输入账号密码登陆
    .用例3
    .用例4
                                                        [100%]
    
    ============================== 4 passed in 0.03s ==============================
    Process finished with exit code 0
    

      scope = “module”:与class相同,只从.py文件开始引用fixture的位置生效

    scope = “session”:用法将在conftest.py文章内详细介绍
    session的作用范围是针对.py级别的,module是对当前.py生效,seesion是对多个.py文件生效
    session只作用于一个.py文件时,作用相当于module
    所以session多数与contest.py文件一起使用,做为全局Fixture

    2、params:

    Fixture的可选形参列表,支持列表传入
    默认None,每个param的值
    fixture都会去调用执行一次,类似for循环
    可与参数ids一起使用,作为每个参数的标识,详见ids
    被Fixture装饰的函数要调用是采用:Request.param(固定写法,如下图)
    

      

    import pytest
    
    
    @pytest.fixture(params=[1, 2, {'a': 1, 'b': 2}, {'A': 1, 'B': 2}])
    def demo(request):
        return request.param
    
    
    def test_demo(demo):
        print("列表值:{}".format(demo))
    
    
    if __name__ == '__main__':
        pytest.main()
    

      结果

    ============================= test session starts =============================
    platform win32 -- Python 3.7.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: E:\FYR\python\111
    plugins: html-3.1.1, metadata-1.11.0collected 4 items
    
    test_fixture1.py                                                     [100%]
    
    ============================== 4 passed in 0.03s ==============================.列表值:1
    .列表值:2
    .列表值:{'a': 1, 'b': 2}
    .列表值:{'A': 1, 'B': 2}
    
    Process finished with exit code 0
    

      

    '''
    request 是 pytest的内置fixture
    '''
    
    import pytest
    
    # 测试数据
    test_data = ["user1", "user2"]
    
    
    @pytest.fixture(params=test_data)
    def register_users(request):
        # 获取当前的测试数据
        user = request.param
        print("setup前置函数拿着这个账号去注册:%s" % user)
        result = "success"
        return user, result
    
    
    def test_register(register_users):
        user, result = register_users
        print("在测试用例里面里面获取到当前测试数据:%s" % user)
        print(result)
        assert result == "success"
    
    
    @pytest.fixture(autouse=True)
    def show_request(request):
        print("\n=======================request start=================================")
        print("request.module==", request.module)
        print("request.functione==", request.function)
        print("request.cls==", request.cls)
        print("request.fspath==", request.fspath)
        print("request.fixturenames==", request.fixturenames)
        print("request.fixturename==", request.fixturename)
        print("request.scope==", request.scope)
        print("\n=======================request end=================================")
    
    
    if __name__ == '__main__':
        print(11)
    

      

     3、ids:

    用例标识ID
    与params配合使用,一对一关系
    举个栗子:
    未配置ids之前,用例:

    import pytest
    
    
    @pytest.fixture(params=[1, 2, {'a': 1, 'b': 2}, {'A': 1, 'B': 2}],ids=["one","two","three","four"])
    def demo(request):
        return request.param
    
    
    def test_demo(demo):
        print("列表值:{}".format(demo))
    
    
    if __name__ == '__main__':
        pytest.main()
    #使用前后的区别

      5、Name:

    fixture的重命名
    通常来说使用 fixture 的测试函数会将 fixture 的函数名作为参数传递,但是 pytest 也允许将fixture重命名
    如果使用了name,那只能将name传如,函数名不再生效
    调用方法:@pytest.mark.usefixtures(‘fixture1’,‘fixture2’)
    

      结果

    ============================= test session starts =============================
    platform win32 -- Python 3.7.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: E:\FYR\python\111
    plugins: html-3.1.1, metadata-1.11.0collected 2 items
    
    test_fixture1.py .使用name参数后,传入重命名函数,执行成功
    E
    test setup failed
    file E:\FYR\python\111\test_fixture1.py, line 17
      def test_2(test_name):
    E       fixture 'test_name' not found
    

      

    2.2 fixture作为参数传入

      定义fixture跟定义普通函数差不多,唯一区别就是在函数上加个装饰器@pytest.fixture(),fixture命名不要用test_开头,跟用例区分开。用例才是test_开头的命名。

      fixture是可以有返回值的,如果没return默认返回None。用例调用fixture的返回值,直接就是吧fixture的函数名称当成变量名称,

    import pytest
    
    @pytest.fixture()
    def user():
        print("获取用户名")
        a = "admin"
        return a
    def test_1(user):
        print("a==", user)
        assert user == "admin"
    
    if __name__ == "__main__":
        pytest.main(["-s", "test_fixture1.py"])

    结果如下:

    ============================= test session starts =============================
    platform win32 -- Python 3.7.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: E:\FYR\python\111
    plugins: html-3.1.1, metadata-1.11.0
    collected 1 item
    
    test_fixture1.py 获取用户名
    a== admin
    .
    
    ============================== 1 passed in 0.16s ==============================
    
    Process finished with exit code 0
    

      2.3error和failed区别

    测试结果一般有三种:passed、failed、error。(skip的用例除外)

    如果在test_用例里面断言失败,那就是failed

    import pytest
    
    
    @pytest.fixture()
    def user():
        print("获取用户名")
        a = "admin"
    
        return a
    def test_1(user):
        assert user == "admin111"
    
    
    if __name__ == "__main__":
        pytest.main(["-s", "test_fixture1.py"])
    

      结果如下:

    ============================= test session starts =============================
    platform win32 -- Python 3.7.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: E:\FYR\python\111
    plugins: html-3.1.1, metadata-1.11.0
    collected 1 item
    
    test_fixture1.py 获取用户名
    F
    
    ================================== FAILURES ===================================
    ___________________________________ test_1 ____________________________________
    
    user = 'admin'
    
        def test_1(user):
    >       assert user == "admin111"
    E       AssertionError: assert 'admin' == 'admin111'
    E         - admin111
    E         ?      ---
    E         + admin
    
    test_fixture1.py:11: AssertionError
    =========================== short test summary info ===========================
    FAILED test_fixture1.py::test_1 - AssertionError: assert 'admin' == 'admin111'
    ============================== 1 failed in 0.15s ==============================
    
    Process finished with exit code 0
    

      

    如果在fixture里面断言失败了,那就是error

    import pytest
    
    
    @pytest.fixture()
    def user():
        print("获取用户名")
        a = "admin"
        assert a == "admin123"
        return a
    
    def test_1(user):
        assert user=="admin"
    
    
    if __name__ == "__main__":
        pytest.main(["-s", "test_fixture1.py"])
    

      结果如下:

    ============================= test session starts =============================
    platform win32 -- Python 3.7.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: E:\FYR\python\111
    plugins: html-3.1.1, metadata-1.11.0
    collected 1 item
    
    test_fixture1.py 获取用户名
    E
    
    =================================== ERRORS ====================================
    __________________________ ERROR at setup of test_1 ___________________________
    
        @pytest.fixture()
        def user():
            print("获取用户名")
            a = "admin"
    >       assert a == "admin123"
    E       AssertionError: assert 'admin' == 'admin123'
    E         - admin123
    E         ?      ---
    E         + admin
    
    test_fixture1.py:8: AssertionError
    =========================== short test summary info ===========================
    ERROR test_fixture1.py::test_1 - AssertionError: assert 'admin' == 'admin123'
    ============================== 1 error in 0.16s ===============================
    
    Process finished with exit code 0
    

     四、request.config.getoption介绍

    import pytest
    
    
    def pytest_addoption(parser):
        parser.addoption("--name", action="store", default="zhangsan", help="my option: name")
        parser.addoption("--tel", action="store", default="18266669999", help="my option: tel")
    
    
    @pytest.fixture(scope='function')  # 根据类型,显示作用范围
    def start_settings(request):
        # 获取--name
        name = request.config.getoption("--name")  # 返回自定义变量的值
        tel = request.config.getoption("--tel")  # 返回自定义变量的值
    
        yield name, tel  # 返回给测试用例使用
    
    
    def test_case1(start_settings):
        name, tel = start_settings
        print("name===", name)
        print("tel===", tel)
    

      

     

  • 相关阅读:
    flexible.js 移动端自适应方案
    Vue为什么不能检测数组变动
    Vue 组件间通信六种方式
    训练首个神经网络:基本分类
    对seq2seq的粗浅认识
    数学模型的过拟合和欠拟合
    在二叉树中寻找值最大的节点并返回——LintCode入门
    Android 包管理机制
    自定义View的三种实现方式及自定义属性使用介绍
    Paint.setFlags中flag意义及使用方法
  • 原文地址:https://www.cnblogs.com/mumianhuasayyes/p/15817121.html
Copyright © 2020-2023  润新知