『德不孤』Pytest框架 — 13、Pytest中Fixture裝飾器(三)

9、ids參數說明

ids參數就是給每一個變數起一個別名。

示例:

import pytest

data = [("孫悟空", 666), ("豬八戒", 777), ("沙和尚", 888)]


# ids參數的個數要與params參數的個數相同,用的很少
@pytest.fixture(params=data, ids=['suk', 'zbj', 'shs'])
def need_data(request):
    return request.param


def test_data(need_data):
    print(f"測試人物:{need_data[0]}")
    print(f"測試分數:{need_data[1]}")


if __name__ == '__main__':
    pytest.main()

"""
之前的測試結果:
test_01.py::test_data[need_data0] 測試人物:孫悟空
測試分數:666
PASSED
test_01.py::test_data[need_data1] 測試人物:豬八戒
測試分數:777
PASSED
test_01.py::test_data[need_data2] 測試人物:沙和尚
測試分數:888
PASSED

加上ids參數後的執行結果:只是[]的內容變化了,這就是ids參數的作用
test_01.py::test_data[suk] 測試人物:孫悟空
測試分數:666
PASSED
test_01.py::test_data[zbj] 測試人物:豬八戒
測試分數:777
PASSED
test_01.py::test_data[shs] 測試人物:沙和尚
測試分數:888
PASSED
"""

10、name參數說明

name參數就是給Fixture修飾的方法起個別名。

示例:

import pytest

data = [("孫悟空", 666), ("豬八戒", 777), ("沙和尚", 888)]


# ids參數的個數要與params參數的個數相同,用的很少
@pytest.fixture(params=data, name="abc")
def need_data(request):
    return request.param

# 注意,如果定義了name屬性,用例的方法參數就需要傳入name屬性定義的值。
# 否則將會報錯。
# 還有用例中調用參數的使用,也需要使用name定義的別名。
# 即:當取了別名之後,那麼原來的方法名就用不了了。
def test_data(abc):
    print(f"測試人物:{abc[0]}")
    print(f"測試分數:{abc[1]}")


if __name__ == '__main__':
    pytest.main()

"""
執行結果:

test_01.py::test_data[abc0] 測試人物:孫悟空
測試分數:666
PASSED
test_01.py::test_data[abc1] 測試人物:豬八戒
測試分數:777
PASSED
test_01.py::test_data[abc2] 測試人物:沙和尚
測試分數:888
PASSED
"""

11、scope參數說明

scope參數有四個級別:function(默認),class,module,session。

作用範圍:session > module > class > function

  • scope="function":@pytest.fixture()裝飾器如果不寫參數,默認參數就是scope="function"。它的作用範圍是,在每個測試用例執行的前(後)運行一次。
  • scope="class":@pytest.fixture()裝飾器為class級別的時候,Fixture方法只在此class里所有用例開始執行前(後)執行一次。與class中的function沒有關係。
  • scope="module":@pytest.fixture()裝飾器為module級別的時候,在一個.py腳本中所有用例開始執行前(後)執行一次。
  • scope="session":@pytest.fixture()裝飾器為session級別的時候,是可以跨.py模組調用的,每個.py文件就是module。

(1)scope="function"

import pytest


@pytest.fixture(scope="function")
def login():
    print("打開APP")
    print("輸入帳號,密碼,進行登錄")
    yield  # 當用例執行完成後,執行yield後的程式碼
    print("關閉APP")


def test_add_cart(login):
    print("添加購物車--需要登錄")


def test_browser_goods():
    print("瀏覽商品--不需要登錄")


if __name__ == '__main__':
    pytest.main()


"""
執行結果: 只作用域方法或者函數範圍

test_01.py::test_add_cart 打開APP
輸入帳號,密碼,進行登錄
添加購物車--需要登錄
PASSED關閉APP

test_01.py::test_browser_goods 瀏覽商品--不需要登錄
PASSED
"""

(2)scope="class"

import pytest


@pytest.fixture(scope="class")
def login():
    print("\nscope=class 作用域的前置函數\n")
    yield  # 當用例執行完成後,執行yield後的程式碼
    print("\n\nscope=class 作用域的後置函數")


class Test_Demo:

    def test_add_cart(self, login):
        print("添加購物車--測試用例")

    def test_add_address(self):
        print("添加收貨地址--測試用例")


if __name__ == '__main__':
    pytest.main()

"""
執行結果: 只在測試類開始前後執行了

scope=class 作用域的前置函數

添加購物車--測試用例
PASSED
test_01.py::Test_Demo::test_add_address 添加收貨地址--測試用例
PASSED

scope=class 作用域的後置函數
"""

(3)scope="module"

import pytest


@pytest.fixture(scope="module")
def login():
    print("\nscope=module 作用域的前置函數\n")
    yield  # 當用例執行完成後,執行yield後的程式碼
    print("\n\nscope=module 作用域的後置函數")

# 如果該用例不傳入fixture方法,該用例會優先與fixture前置執行
def test_browser_goods(login):
    print("瀏覽商品--不需要登錄")

class Test_Demo:

    def test_add_cart(self, login):
        print("添加購物車--測試用例")

    def test_add_address(self):
        print("添加收貨地址--測試用例")

class Test_Demo2:

    def test_add_cart(self, login):
        print("第2次-添加購物車--測試用例")

    def test_add_address(self):
        print("第2次-添加收貨地址--測試用例")


if __name__ == '__main__':
    pytest.main()

"""
執行結果:
說明一下:scope=module時,整個.py模組中fixture只執行一次

scope=module 作用域的前置函數

瀏覽商品--不需要登錄
PASSED
test_01.py::Test_Demo::test_add_cart 添加購物車--測試用例
PASSED
test_01.py::Test_Demo::test_add_address 添加收貨地址--測試用例
PASSED
test_01.py::Test_Demo2::test_add_cart 第2次-添加購物車--測試用例
PASSED
test_01.py::Test_Demo2::test_add_address 第2次-添加收貨地址--測試用例
PASSED

scope=module 作用域的後置函數

"""

(4)scope="session"

test_01.py文件中的用例。

import pytest

@pytest.fixture(scope="session")
def login():
    print("\nscope=session 作用域的前置函數\n")
    yield  # 當用例執行完成後,執行yield後的程式碼
    print("\n\nscope=session 作用域的後置函數")

# 如果該用例不傳入fixture方法,該用例會優先與fixture前置執行
def test_browser_goods(login):
    print("瀏覽商品--不需要登錄")

class Test_Demo:

    def test_add_cart(self, login):
        print("添加購物車--測試用例")

    def test_add_address(self):
        print("添加收貨地址--測試用例")


if __name__ == '__main__':
    pytest.main()

test_02.py文件中的用例。

# 如果該用例不傳入fixture方法,該用例會優先與fixture前置執行
def test_browser_goods():
    print("第2次-瀏覽商品--不需要登錄")

class Test_Demo2:

    def test_add_cart(self):
        print("第2次-添加購物車--測試用例")

    def test_add_address(self):
        print("第2次-添加收貨地址--測試用例")

all.py文件內容:

import pytest

if __name__ == '__main__':
    pytest.main()

"""
執行結果:只在該包內執行一次fixture前後置

scope=session 作用域的前置函數

瀏覽商品--不需要登錄
PASSED
test_01.py::Test_Demo::test_add_cart 添加購物車--測試用例
PASSED
test_01.py::Test_Demo::test_add_address 添加收貨地址--測試用例
PASSED
test_02.py::test_browser_goods 第2次-瀏覽商品--不需要登錄
PASSED
test_02.py::Test_Demo2::test_add_cart 第2次-添加購物車--測試用例
PASSED
test_02.py::Test_Demo2::test_add_address 第2次-添加收貨地址--測試用例
PASSED

scope=session 作用域的後置函數
"""

說明:

我把session作用域的Fixture寫在了test_01.py文件中,其實應該提取出來寫到conftest.py文件中。(後面文章會說明)

all.py文件就是為了執行所有測試用例,pytest.ini文件中配置的模糊匹配查詢,這樣兩個文件中的用例就都能執行到了。

這裡就是一個練習,寫的十分不規範,理解其意思就可以。

12、autouse參數說明

示例:實全部用例的前後置

很簡單,只需要把Fixture中的autouse參數設置為True即可。

Fixture裝飾器會自動執行作用域範圍內的所有用例的前後置。

import pytest

@pytest.fixture(autouse=True)
def login():
    print("輸入帳號,密碼,進行登錄")

def test_add_cart():  # 不需要傳入fixture方法
    print("添加購物車--需要登錄")

def test_add_address():  # 不需要傳入fixture方法
    print("添加收貨地址--需要登錄")


if __name__ == '__main__':
    pytest.main()

"""
執行結果:

輸入帳號,密碼,進行登錄
添加購物車--需要登錄
PASSED輸入帳號,密碼,進行登錄
添加收貨地址--需要登錄
PASSED
"""