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)

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM