基於pytest的接口測試


最近要開展接口測試,起初打算使用公司已有的Fitnesse測試工具來進行接口測試。過程中發現,構造接口字段數據、測試數據都比較困難,接口參數多的時候,用例量就會很多,關鍵執行速度還慢。所以放棄了。

找了一些其它工具,都不太能解決數據構造困難的問題。找不到工具,就直接使用代碼來實現。考慮到代碼量,結合網上的一些推薦,決定使用python+pytest來編寫接口自動化用例。

決定了語言和框架,接下來要考慮一下實現需求。

1.一套用例可以測試多套環境

2.可以被jenkins調度執行

3.擁有測試報告

4.接口中某些字段值在每次請求中不重復

5.可以多接口關聯測試

6.構造的表數據可以和接口字段數據關聯

7.pytest用例和實際用例數據要分離,方便維護

8.針對多樣的響應內容,具備多樣的斷言方式。

 


 

需求一:一套用例可以測試多套環境

公司的測試環境不止一套,希望在使用接口自動化用例時,可以隨意的切換被測環境。

為了滿足這個需求,首先要完成接口地址等信息的獨立配置,而且是要按照一套環境的維度去管理信息。

 我的做法如上圖,首先我給每套環境設置了一個別名,比如上圖中的lion環境,然后設計了一個服務去持久化變量值信息(變量名稱所有環境保存一致)。

 

 

接着將環境名稱和變量名稱,組合起來,保存到redis中(如上圖),供后續接口自動化用例讀取並使用。

 

環境信息搞定之后,接下來的任務就是,設計一種方法讓接口自動化用例使用環境信息。

這里采用的方法是,在執行時,指定環境別名。

pytest的用例有多種執行方式,這里使用pytest.main()來啟動,通過將pytest.main()寫入一個py文件中,如下面代碼。

 
         
memberCenter.py

1
if __name__ == "__main__": 2 if (len(sys.argv) == 2): 3 _, env = sys.argv 4 else: 5 env = 'lion' 6 BaseUtil.initTest(env) 7 pytest.main(['--alluredir=./allure-results', '--maxfail=5','-s','-rA', 'testcase/membercenter/'])

 啟動時,接受一個參數env,並將env作為屬性添加到Context中,供用例使用。

BaseUtil.py
from context import Context as ct
def initTest(env):
 ct.env = env 

調用命令:

 

 這里就指定了測試環境的別名為lion。

有了環境別名,再加上統一的變量名稱,就可以使用下面的方式,去redis獲取對應的變量值了。

 

 以上就實現了多環境測試的需求。后續只要維護好環境別名、變量名稱和變量值就可以了。

 


 

需求二: 可以被jenkins調度執行

這個比較簡單,通過參數化構建就可以。

 

 不過為了不影響Jenkins所在服務器,我使用了docker去執行用例

下面是Dockerfile的配置

 

 下面是jenkins中的Execute shell

 1 echo "清除歷史報告記錄"
 2 cd ${WORKSPACE}
 3 cd allure-report && rm -rf *
 4 cd ${WORKSPACE}
 5 cd allure-results && rm -rf *
 6 
 7 echo "開始執行命令"
 8 cd ${WORKSPACE}
 9 
10 function del_ci {
11   echo "$1"
12   docker stop chbifacetest
13   docker rm chbifacetest
14   docker rmi hbifacetest:1.1
15 }
16 
17 docker inspect --format '{{.State.Running}}' chbifacetest && del_ci "刪除容器和鏡像"
18 
19 
20 docker build -t hbifacetest:1.1 .
21 docker run  -v ${WORKSPACE}/allure-results:/usr/local/hbifacetest/allure-results -v ${WORKSPACE}/allure-report:/usr/local/hbifacetest/allure-report --name chbifacetest hbifacetest:1.1 ${pymainfile} ${testEnv}
22 echo "執行結束"

 


 

需求三  擁有測試報告

測試報告使用的是Allure,主要是美觀且配置簡單,(參考:https://docs.qameta.io/allure/#_pytest)

 step1:配置報告路徑

添加一個參數--alluredir=./allure-results

 

 step2:編寫用例時,添加注釋

 

 step3:在jenkins中安裝插件

 

 step4:在job中配置報告路徑

 

step5:在另一個job中添加執行計划

 

 

 

 

step6:查看報告

 


 

需求四:接口中某些字段值在每次請求中不重復


這里通過python的一個庫factory-boy來實現該需求。(參考:https://www.cnblogs.com/moonpool/p/11352705.html)

大概的原理就是將每個接口當做一個對象來處理,通過factory-boy給每個字段添加值,可以是固定值,也可以是隨機值。然后將對象轉成dict,並發送請求。(復雜對象轉dict比較麻煩,參考:https://www.cnblogs.com/moonpool/p/11454902.html)

如下圖中的紅框部分字段,每次請求都將是不同的值。

 

 


 

需求五: 可以多接口關聯測試

針對這個需求,實現的主要思路是,可以在一條Pytest用例中,拿到所有接口的請求和響應參數。

這里利用了pytest中fixture,將每個接口的http請求方法封裝成fixture,后續傳遞給pytest用例使用。同理實現了 加載用例數據的Fixture

 1 #接口Fixture
 2 @pytest.fixture(scope="function")
 3 def member_borrower_addBorrower_http_json():
 4     def _member_borrower_addBorrower_http_json(dict={"key": "value"}):
 5         r = ht.post_json(url=member_borrower_addBorrower_url, json=dict,headers=headers_json)
 6         return r
 7 
 8     return _member_borrower_addBorrower_http_json
 9 
10 @pytest.fixture(scope="function")
11 def member_borrower_updateBorrower_http_json():
12     def _member_borrower_updateBorrower_http_json(dict={"key": "value"}):
13         r = ht.post_json(url=member_borrower_updateBorrower_url, json=dict,headers=headers_json)
14         return r
15 
16     return _member_borrower_updateBorrower_http_json
17 
18 #加載用例數據的Fixture
19 @pytest.fixture(scope="function",params=addBorrower)
20 def test_member_borrower_addBorrower(request):
21     dict=request.param
22     return dict
23 
24 @pytest.fixture(scope="function",params=updateBorrower)
25 def test_member_borrower_updateBorrower(request):
26     dict=request.param
27     return dict

下面是用例數據,可以看到request中傳遞的是一個函數,函數執行后,可以拿到兩個請求的請求參數。

 

 

 下面的是pytest用例,可以看到用例中可以同時維護兩個請求接口的請求參數和響應內容

這里例子比較簡單,更新請求中,需要使用到添加響應中的data字段值。


 

需求六 構造的表數據可以和接口字段數據關聯

有時候沒有辦法,通過其它接口的調用得到的信息,來為當前測試接口做數據入參。可偏偏需要在數據庫中存在數據,才可以調用當前測試接口。

可以利用Factory-boy和sqlalchemy來實現這個需求。利用Factory-boy生成隨機數據,利用sqlalchemy將數據入庫。

例如下面pytest用例的紅框部分,就是在插入數據,並使用數據中black_index,作為當前測試接口的請求入參

 

 

 下面是CreateMBL函數的實現

 

 

 下面是Factory-boy生成數據的代碼  (參考:https://www.cnblogs.com/moonpool/p/11370502.html)

 1 import factory
 2 import factory.fuzzy
 3 from sqlalchemy import Column,String,BIGINT,INT,VARCHAR,DECIMAL, Unicode, create_engine
 4 from sqlalchemy.ext.declarative import declarative_base
 5 from sqlalchemy.orm import scoped_session, sessionmaker
 6 from .dbsession import FintechDBSession
 7 from baseutil.pr import Provider
 8 
 9 Base = declarative_base()
10 
11 class member_black_list(Base):
12     # 表的名字:
13     __tablename__ = 'member_black_list'
14 
15     # 表的結構:
16     black_index=Column(BIGINT(), primary_key=True)
17     black_type=Column(INT())
18     real_name=Column(VARCHAR(120))
19     card_id=Column(VARCHAR(40))
20     phone=Column(VARCHAR(40))
21     remark=Column(VARCHAR(1024))
22     oper_id=Column(VARCHAR(40))
23     oper_name=Column(VARCHAR(255))
24     create_time = Column(VARCHAR(14))
25     update_time=Column(VARCHAR(14))
26     status=Column(INT())
27     reason=Column(VARCHAR(512))
28     examine_status=Column(INT())
29     effective_start_date=Column(VARCHAR(8))
30     effective_end_date=Column(VARCHAR(8))
31     black_source=Column(INT())
32     version=Column(INT())
33 
34 factory.Faker.add_provider(Provider)
35 
36 class member_black_list_factory(factory.alchemy.SQLAlchemyModelFactory):
37     class Meta:
38         model = member_black_list
39         sqlalchemy_session = FintechDBSession
40 
41     black_index = factory.Faker("randomInt")
42     black_type = 1
43     real_name = factory.Faker("name", locale="zh_CN")
44     card_id = factory.Faker("idNumber")
45     phone = factory.fuzzy.FuzzyText("1333", 6, "1", "1234567890")
46     remark = "自動化接口測試"
47     oper_id = "100000003508"
48     oper_name = "test1234"
49     create_time = factory.Faker("currentTimeByFormat")
50     update_time = factory.Faker("currentTimeByFormat")
51     status = 1
52     reason = "自動化接口測試"
53     examine_status = 1
54     effective_start_date = factory.Faker("datebyday", days=0, ft="%Y-%m-%d")
55     effective_end_date = factory.Faker("datebyday", days=1, ft="%Y-%m-%d")
56     black_source = 0
57     version = 0

 

需求七 pytest用例和實際用例數據要分離,方便維護

在需求五中依據可以看出, pytest用例和實際用例數據是分離。

大部分接口自動化做法是使用excel去維護用例,但是當接口或響應字段比較多的時候,編寫用例比較麻煩。如果出現接口字段變更,修改用例也變得比較麻煩。

首先pytest用例和實際用例分離是必須的,接下來就是怎么維護用例的問題。

下面就是我的實際用例數據,可以看到request中通過不同的參數,可以生成不同的請求數據。至於怎么執行用例,參考https://www.cnblogs.com/moonpool/p/11351859.html

 

 


需求八 針對多樣的響應內容,具備多樣的斷言方式

 

起初在用例的response中,只存放了一個dict,如下圖,但是有時候響應內容(json格式)是多樣的,需要斷言的字段不一定都在json的頂層結構中,可能還會出現嵌套dict以及list的情況。

 

 下面是我的實現。主要的思想就是根據不同的斷言需求,傳遞給不同的斷言方法。

 

用例中調用下面的函數,可以生成一批斷言集合。

 

當斷言需求類型是dict的時候,會調用下面的函數。

 

 

 用例response編寫,指定不同的斷言需求

 

pytest 用例使用,如紅框部分,結合上面的用例的斷言需求,在用例執行時,實時傳入實際響應內容。再遍歷執行斷言函數集合。就完成了多樣的斷言需求。

 


免責聲明!

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



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