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測試框架的使用