pytest數據參數化和數據驅動yaml的簡單使用


Pytest參數化

  • @pytest.mark.parametrize(argnames, argvalues)
  • argnames: 要參數化的變量, string(逗號分隔), list, tuple
  • argvalues: 參數化的值,list, list[tuple]

新建一個 簡單的 test_demo.py 代碼內容為:

class TestClass:
    @pytest.mark.parametrize('a,b', [(1, 2), (2, 3), (4, 5)])
    def test_a(self, a, b):
        # print(f'login name is {}')
        print(a + b)
        print('1')

    def test_b(self):
        print('2')

    def test_c(self, login):
        print(f'login name is {login}')
        print('3')
然后在控制台中 輸入 上一節 學到的 -k(指定函數) -v(打印詳細內容) -s (輸出print內容)
pytest -v -k test_a -s

可以看到想要的結果

測試結構化的簡單demo

讀取yaml文件, 先建立一個數組的demo
yaml的語法 可以參考 https://www.runoob.com/w3cnote/yaml-intro.html

-
  - 10
  - 20
-
  - 30
  - 40

然后建立一個Pytest去讀取

import pytest
import yaml

class TestClass:
    @pytest.mark.parametrize('a,b', yaml.safe_load(open('env.yml')))
    def test_a(self, a, b):
        print(a + b)
        print('1')

常常我們需要結構化我們的測試環境,一般配置文件放在yaml中,簡單的讀取

yml 文件內容:
-
  languages:
    - Ruby
    - Perl
    - Python 
  websites:
    YAML: yaml.org 
    Ruby: ruby-lang.org 
    Python: python.org 
    Perl: use.perl.org

  dev: # 生產環境
    ip: 127.0.0.1

---- # 注意點 當不知道自己寫的yml格式對象是否正確的時候可以通過讀取出來來驗證
class TestClass:
   def test_b(self):
        print(yaml.safe_load(open('env.yml')))
# 然后執行命令行: pytest -v -k test_b -s 就可以看到寫的yml

# 下面是讀取配置文件的寫法,前提是知道自己的yml是什么樣子
import pytest
import yaml
class TestClass:
    @pytest.mark.parametrize('env', yaml.safe_load(open('env.yml')))
    def test_a(self, env):
        if "dev" in env:
            # print(env) 可以先打印出來看看 是什么結構
            print(f'生產環境, ip地址為{env.get("dev").get("ip")}')
        elif "test" in env:
            print('測試環境')
然后執行命令: pytest -v -k test_a -s 就可以看到執行的結果

關於和unittest的一些差不多的用法

有兩個前置方法,兩個后置方法

  • setup()
  • setupClass()
  • teardown()
  • teardownClass()

函數級別用法demo, 新建一個test_demo2.py文件:

import pytest

def setup_module():
    print("py模塊開始前只執行一次,打開)


def teardown_module():
    print("py模塊結束后只執行一次,關閉")


def setup_function():
    print("函數開始前都執行setup_function)


def teardown_function():
    print("函數結束后都執行teardown_function")


def test_one():
    print("one")


def test_two():
    print("two")


if __name__ == '__main__':
    pytest.main(["-q", "-s", "-ra", "test_demo2.py"])  # -q 簡單顯示結果

執行即可得到結果

類級別用法demo, 新建一個test_demo3.py文件:

import pytest


class TestCase():
    def setup_class(self):
        print("====整個測試類開始前只執行一次setup_class====")

    def teardown_class(self):
        print("====整個測試類結束后只執行一次teardown_class====")

    def setup_method(self):
        print("==類里面每個用例執行前都會執行setup_method==")

    def teardown_method(self):
        print("==類里面每個用例結束后都會執行teardown_method==")

    def setup(self):
        print("=類里面每個用例執行前都會執行setup=")

    def teardown(self):
        print("=類里面每個用例結束后都會執行teardown=")

    def test_three(self):
        print("one")

    def test_four(self):
        print("two")


if __name__ == '__main__':
    pytest.main(["-q", "-s", "-ra", "test_demo3.py"])  # -q 簡單顯示結果

當遇到一些需要針對某個測試用例使用的,比如登陸什么的時候,上面這種針對整個腳本全局生效的,明顯就不合適使用了,所以要用上一節提到的 @pytest.fixture(),就可以解決這些場景,但是當有多個測試用例文件(test_*.py)的所有用例都需要用登錄功能來作為前置操作,那就不能把登錄功能寫到某個用例文件中去,所以需要一個conftest.py來管理一些全局的fixture

conftest.py配置fixture注意事項

  • conftest.py 會被pytest 默認讀取,不用導入
  • 文件名是固定的,一個包可以有一個,一個項目可以有多個

項目結構如下:

conftest.py代碼

最頂層的conftest.py,一般寫全局的fixture

import pytest

# scope:可以理解成fixture的作用域,默認:function,還有class、module、package、session四個【常用】
# function 每一個函數或方法都會調用
# class 每一個類調用一次,一個類可以有多個方法
# module,每一個.py文件調用一次,該文件內又有多個function和class
# session 是多個文件調用一次,可以跨.py文件調用,每個.py文件就是module

@pytest.fixture(scope="session")
def login():
    print("====登錄功能,返回賬號,token===")
    name = "lakes"
    token = "something you ned guess!"
    yield name, token
    print("====退出登錄!!!====") # 退出登錄,最后才會執行

# autouse:默認:False,需要用例手動調用該fixture;如果是True,所有作用域內的測試用例都會自動調用該fixture
@pytest.fixture(autouse=True)
def get_info(login):
    name, token = login
    print(f"== 每個用例都調用的外層fixture:打印用戶token: {token} ==")`

@pytest.fixture()
def get_test():
    print('測試autouse=False')  # 不會打印

test_demo1.py

def test_get_info(login):
    name, token = login
    print("***基礎用例:獲取用戶個人信息***")
    print(f"用戶名:{name}, token:{token}")

01_run.py 運行主文件

import pytest

if __name__ == '__main__':
    pytest.main(["-s", "../test_01/"]) # 執行入口

主要的測試可以正常運行的話,就可以加入一些其他平台的測試

選了微博小紅書和今日頭條來做實驗,現在的目錄結構是這這樣子

外部是上面的內容。加了上個新的文件夾,分別是 test_redbook 、test_toutiao、 test_weibo

test_redbook/test_red1.py 文件內容 什么都不加,只是調用最外層的conftest.py的 fixture,login

def test_no_fixture(login):
    print("==沒有__init__測試用例,我進入小紅書了==", login) # 輸出打印的只是這句話

test_toutiao/conftest.py 項目里面除了最外層的conftest.py 還新增了一個conftest, 這個這個目錄下的conftest.py, 最外層的可以用,目錄下的也可以用

import pytest

# 針對頭條獨有的,function代表每一個函數或方法都會調用
@pytest.fixture(scope="function")
def open_toutiao(login):
    name, token = login
    print(f"&&& 用戶 {name} 返回頭條首頁 &&&")

test_toutiao/test_t1.py 來測試function是否生效,在測試用例執行前會執行一遍,這里執行了兩次

class TestToutiao:
    def test_case1_01(self, open_toutiao):
        print("查看頭條今日關注")

    def test_case1_02(self, open_toutiao):
        print("查看頭條今日的用戶")

test_weibo/conftest.py 這個跟上面的一樣,但是scope進行了更改

import pytest


@pytest.fixture(scope="module")
def open_weibo(login):
    name, token = login
    print(f"###用戶 {name} 打開微博 ###")


@pytest.fixture()
def close_weibo(login):
    name, token = login
    print(f"###用戶 {name} 離開了微博 ###")

test_weibo/test_case1.py 來測試function是否生效,在測試用例中只執行了一遍

def test_case2_01(open_weibo):
    print("微博超話內容")


def test_case2_02(open_weibo):
    print("微博熱點內容")


def test_case2_04(close_weibo):
    print("微博關閉44444444")


def test_case2_05(close_weibo):
    print("微博關閉555555")

然后直接執行 python 01_run.py
完。
參考: 小菠蘿測試筆記 https://www.cnblogs.com/poloyy/p/12641991.html
下一次隨筆寫的是測試報告的美化與定制 Allure測試框架的使用


免責聲明!

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



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