<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python+Requests+Pytest+YAML+Allure實(shí)現(xiàn)接口自動(dòng)化

          共 11283字,需瀏覽 23分鐘

           ·

          2021-07-12 10:06

          本項(xiàng)目實(shí)現(xiàn)接口自動(dòng)化的技術(shù)選型:Python+Requests+Pytest+YAML+Allure ,主要是針對(duì)之前開(kāi)發(fā)的一個(gè)接口項(xiàng)目來(lái)進(jìn)行學(xué)習(xí),通過(guò) Python+Requests 來(lái)發(fā)送和處理HTTP協(xié)議的請(qǐng)求接口,使用 Pytest 作為測(cè)試執(zhí)行器,使用 YAML 來(lái)管理測(cè)試數(shù)據(jù),使用 Allure 來(lái)生成測(cè)試報(bào)告

          接口項(xiàng)目開(kāi)發(fā)學(xué)習(xí):

          使用Flask開(kāi)發(fā)簡(jiǎn)單接口(1)--GET請(qǐng)求接口(https://www.cnblogs.com/wintest/p/12728095.html) 

          使用Flask開(kāi)發(fā)簡(jiǎn)單接口(2)--POST請(qǐng)求接口(https://www.cnblogs.com/wintest/p/12731508.html) 

          使用Flask開(kāi)發(fā)簡(jiǎn)單接口(3)--引入MySQL (https://www.cnblogs.com/wintest/p/12741772.html) 

          使用Flask開(kāi)發(fā)簡(jiǎn)單接口(4)--借助Redis實(shí)現(xiàn)token驗(yàn)證(https://www.cnblogs.com/wintest/p/12777340.html)

          使用Flask開(kāi)發(fā)簡(jiǎn)單接口(5)--數(shù)據(jù)加密處理(https://www.cnblogs.com/wintest/p/12780090.html)

          項(xiàng)目說(shuō)明

          本項(xiàng)目在實(shí)現(xiàn)過(guò)程中,把整個(gè)項(xiàng)目拆分成請(qǐng)求方法封裝、HTTP接口封裝、關(guān)鍵字封裝、測(cè)試用例等模塊。

          首先利用Python把HTTP接口封裝成Python接口,接著把這些Python接口組裝成一個(gè)個(gè)的關(guān)鍵字,再把關(guān)鍵字組裝成測(cè)試用例,而測(cè)試數(shù)據(jù)則通過(guò)YAML文件進(jìn)行統(tǒng)一管理,然后再通過(guò)Pytest測(cè)試執(zhí)行器來(lái)運(yùn)行這些腳本,并結(jié)合Allure輸出測(cè)試報(bào)告

          當(dāng)然,如果感興趣的話(huà),還可以再對(duì)接口自動(dòng)化進(jìn)行Jenkins持續(xù)集成

          GitHub項(xiàng)目源碼地址:https://github.com/wintests/pytestDemo

          項(xiàng)目結(jié)構(gòu)

          • api ====>> 接口封裝層,如封裝HTTP接口為Python接口
          • common ====>> 各種工具類(lèi)
          • core ====>> requests請(qǐng)求方法封裝、關(guān)鍵字返回結(jié)果類(lèi)
          • config ====>> 配置文件
          • data ====>> 測(cè)試數(shù)據(jù)文件管理
          • operation ====>> 關(guān)鍵字封裝層,如把多個(gè)Python接口封裝為關(guān)鍵字
          • pytest.ini ====>> pytest配置文件
          • requirements.txt ====>> 相關(guān)依賴(lài)包文件
          • testcases ====>> 測(cè)試用例

          請(qǐng)求方法封裝

          core/rest_client.py 文件中,對(duì) Requests 庫(kù)下一些常見(jiàn)的請(qǐng)求方法進(jìn)行了簡(jiǎn)單封裝,以便調(diào)用起來(lái)更加方便。

          class RestClient():

              def __init__(self, api_root_url):
                  self.api_root_url = api_root_url
                  self.session = requests.session()

              def get(self, url, **kwargs):
                  return self.request(url, "GET", **kwargs)

              def post(self, url, data=None, json=None, **kwargs):
                  return self.request(url, "POST", data, json, **kwargs)

              def put(self, url, data=None, **kwargs):
                  return self.request(url, "PUT", data, **kwargs)

              def delete(self, url, **kwargs):
                  return self.request(url, "DELETE", **kwargs)

              def patch(self, url, data=None, **kwargs):
                  return self.request(url, "PATCH", data, **kwargs)

              def request(self, url, method, data=None, json=None, **kwargs):
                  url = self.api_root_url + url
                  headers = dict(**kwargs).get("headers")
                  params = dict(**kwargs).get("params")
                  files = dict(**kwargs).get("params")
                  cookies = dict(**kwargs).get("params")
                  self.request_log(url, method, data, json, params, headers, files, cookies)
                  if method == "GET":
                      return self.session.get(url, **kwargs)
                  if method == "POST":
                      return requests.post(url, data, json, **kwargs)
                  if method == "PUT":
                      if json:
                          # PUT 和 PATCH 中沒(méi)有提供直接使用json參數(shù)的方法,因此需要用data來(lái)傳入
                          data = complexjson.dumps(json)
                      return self.session.put(url, data, **kwargs)
                  if method == "DELETE":
                      return self.session.delete(url, **kwargs)
                  if method == "PATCH":
                      if json:
                          data = complexjson.dumps(json)
                      return self.session.patch(url, data, **kwargs)

          HTTP接口 封裝為 Python接口

          api/user.py 文件中,將上面封裝好的HTTP接口,再次封裝為不同的Python接口。不同的Python接口,會(huì)處理不同URL下的請(qǐng)求。

          class User(RestClient):

              def __init__(self, api_root_url, **kwargs):
                  super(User, self).__init__(api_root_url, **kwargs)

              def list_all_users(self, **kwargs):
                  return self.get("/users", **kwargs)

              def list_one_user(self, username, **kwargs):
                  return self.get("/users/{}".format(username), **kwargs)

              def register(self, **kwargs):
                  return self.post("/register", **kwargs)

              def login(self, **kwargs):
                  return self.post("/login", **kwargs)

              def update(self, user_id, **kwargs):
                  return self.put("/update/user/{}".format(user_id), **kwargs)

              def delete(self, name, **kwargs):
                  return self.post("/delete/user/{}".format(name), **kwargs)

          關(guān)鍵字返回結(jié)果類(lèi)

          core/result_base.py 下,定義了一個(gè)空類(lèi) ResultBase ,該類(lèi)主要用于自定義關(guān)鍵字返回結(jié)果。

          class ResultBase():
              pass

          """
          自定義示例:
          result = ResultBase()
          result.success = False
          result.msg = res.json()["
          msg"]
          result.response = res
          "
          ""

          在多流程的業(yè)務(wù)場(chǎng)景測(cè)試下,通過(guò)自定義期望保存的返回?cái)?shù)據(jù)值,以便更好的進(jìn)行斷言。

          關(guān)鍵字封裝

          關(guān)鍵字應(yīng)該是具有一定業(yè)務(wù)意義的,在封裝關(guān)鍵字的時(shí)候,可以通過(guò)調(diào)用多個(gè)Python接口來(lái)完成。在某些情況下,比如測(cè)試一個(gè)充值接口的時(shí)候,在充值后可能需要調(diào)用查詢(xún)接口得到最新賬戶(hù)余額,來(lái)判斷查詢(xún)結(jié)果與預(yù)期結(jié)果是否一致,那么可以這樣來(lái)進(jìn)行測(cè)試:

          • 1, 首先,可以把 充值-查詢(xún) 的操作封裝為一個(gè)關(guān)鍵字,在這個(gè)關(guān)鍵字中依次調(diào)用充值和查詢(xún)的接口,并可以自定義關(guān)鍵字的返回結(jié)果。
          • 2, 接著,在編寫(xiě)測(cè)試用例的時(shí)候,直接調(diào)用關(guān)鍵字來(lái)進(jìn)行測(cè)試,這時(shí)就可以拿到關(guān)鍵字返回的結(jié)果,那么斷言的時(shí)候,就可以直接對(duì)關(guān)鍵字返回結(jié)果進(jìn)行斷言。

          測(cè)試用例層

          根據(jù)用例名分配測(cè)試數(shù)據(jù)

          測(cè)試數(shù)據(jù)位于 data 文件夾下,在這里使用 YAML 來(lái)管理測(cè)試數(shù)據(jù),同時(shí)要求測(cè)試數(shù)據(jù)中第一層的名稱(chēng),需要與測(cè)試用例的方法名保持一致,如 test_get_all_user_infotest_delete_user。

          test_get_all_user_info:
            # 期望結(jié)果,期望返回碼,期望返回信息
            # except_result, except_code, except_msg
            - [True, 0, "查詢(xún)成功"]
          省略
          test_delete_user:
            # 刪除的用戶(hù)名,期望結(jié)果,期望返回碼,期望返回信息
            # username, except_result, except_code, except_msg
            - ["測(cè)試test", True, 0, "刪除用戶(hù)信息成功"]
            - ["wintest3", False, 3006, "該用戶(hù)不允許刪除"]

          這里借助 fixture 方法,我們就能夠通過(guò) request.function.__name__ 自動(dòng)獲取到當(dāng)前執(zhí)行用例的函數(shù)名 testcase_name ,當(dāng)我們傳入測(cè)試數(shù)據(jù) api_data 之后,接著便可以使用 api_data.get(testcase_name) 來(lái)獲取到對(duì)應(yīng)用例的測(cè)試數(shù)據(jù)。

          import pytest
          from testcases.conftest import api_data

          @pytest.fixture(scope="function")
          def testcase_data(request):
              testcase_name = request.function.__name__
              return api_data.get(testcase_name)`

          數(shù)據(jù)準(zhǔn)備和清理

          在接口自動(dòng)化中,為了保證用例可穩(wěn)定、重復(fù)地執(zhí)行,我們還需要有測(cè)試前置操作和后置操作,即數(shù)據(jù)準(zhǔn)備和數(shù)據(jù)清理工作。

          @pytest.fixture(scope="function")
          def delete_register_user():
              """注冊(cè)用戶(hù)前,先刪除數(shù)據(jù),用例執(zhí)行之后,再次刪除以清理數(shù)據(jù)"""
              del_sql = base_data["init_sql"]["delete_register_user"]
              db.execute_db(del_sql)
              logger.info("注冊(cè)用戶(hù)操作:清理用戶(hù)--準(zhǔn)備注冊(cè)新用戶(hù)")
              logger.info("執(zhí)行前置SQL:{}".format(del_sql))
              yield # 用于喚醒 teardown 操作
              db.execute_db(del_sql)
              logger.info("注冊(cè)用戶(hù)操作:刪除注冊(cè)的用戶(hù)")
              logger.info("執(zhí)行后置SQL:{}".format(del_sql))

          在這里,以用戶(hù)注冊(cè)用例為例。對(duì)于前置操作,我們應(yīng)該準(zhǔn)備一條刪除SQL,用于將數(shù)據(jù)庫(kù)中已存在的相同用戶(hù)刪除,對(duì)于后置操作,我們應(yīng)該再執(zhí)行刪除SQL,確保該測(cè)試數(shù)據(jù)正常完成清理工作。

          在測(cè)試用例中,我們只需要在用例上傳入 fixture 的函數(shù)參數(shù)名 delete_register_user ,這樣就可以調(diào)用 fixture 實(shí)現(xiàn)測(cè)試前置及后置操作。當(dāng)然,也可以使用pytest裝飾器 @pytest.mark.usefixtures() 來(lái)完成,如:

          @pytest.mark.usefixtures("delete_register_user")` 

          Allure用例描述

          在這里,我們結(jié)合 Allure 來(lái)實(shí)現(xiàn)輸出測(cè)試報(bào)告,同時(shí)我們可以使用其裝飾器來(lái)添加一些用例描述并顯示到測(cè)試報(bào)告中,以便報(bào)告內(nèi)容更加清晰、直觀、可讀。如使用 @allure.title() 自定義報(bào)告中顯示的用例標(biāo)題,使用 @allure.description() 自定義用例的描述內(nèi)容,使用 @allure.step() 可在報(bào)告中顯示操作步驟,使用 @allure.issue() 可在報(bào)告中顯示缺陷及其鏈接等。

          @allure.step("步驟1 ==>> 注冊(cè)用戶(hù)")
          def step_1(username, password, telephone, sex, address):
              logger.info("步驟1 ==>> 注冊(cè)用戶(hù) ==>> {}, {}, {}, {}, {}".format(username, password, telephone, sex, address))

          @allure.severity(allure.severity_level.NORMAL)
          @allure.epic("針對(duì)單個(gè)接口的測(cè)試")
          @allure.feature("用戶(hù)注冊(cè)模塊")
          class TestUserRegister():
              """用戶(hù)注冊(cè)"""
              @allure.story("用例--注冊(cè)用戶(hù)信息")
              @allure.description("該用例是針對(duì)獲取用戶(hù)注冊(cè)接口的測(cè)試")
              @allure.issue("https://www.cnblogs.com/wintest", name="點(diǎn)擊,跳轉(zhuǎn)到對(duì)應(yīng)BUG的鏈接地址")
              @allure.testcase("https://www.cnblogs.com/wintest", name="點(diǎn)擊,跳轉(zhuǎn)到對(duì)應(yīng)用例的鏈接地址")
              @allure.title(
                  "測(cè)試數(shù)據(jù):【 {username},{password},{telephone},{sex},{address},{except_result},{except_code},{except_msg}】")
              @pytest.mark.single
              @pytest.mark.parametrize("username, password, telephone, sex, address, except_result, except_code, except_msg",
                                       api_data["test_register_user"])
              @pytest.mark.usefixtures("delete_register_user")
              def test_delete_user(self, login_fixture, username, except_result, except_code, except_msg):
          省略` 

          項(xiàng)目部署

          首先,下載項(xiàng)目源碼后,在根目錄下找到 requirements.txt 文件,然后通過(guò) pip 工具安裝 requirements.txt 依賴(lài),執(zhí)行命令:

          pip3 install -r requirements.txt` 

          接著,修改 config/setting.ini 配置文件,在Windows環(huán)境下,安裝相應(yīng)依賴(lài)之后,在命令行窗口執(zhí)行命令:

          pytest

          注意:因?yàn)槲疫@里是針對(duì)自己的接口項(xiàng)目進(jìn)行測(cè)試,如果想直接執(zhí)行我的測(cè)試用例來(lái)查看效果,需要提前部署上面提到的接口項(xiàng)目。

          測(cè)試報(bào)告效果展示

          在命令行執(zhí)行命令:pytest 運(yùn)行用例后,會(huì)得到一個(gè)測(cè)試報(bào)告的原始文件,但這個(gè)時(shí)候還不能打開(kāi)成HTML的報(bào)告,還需要在項(xiàng)目根目錄下,執(zhí)行命令啟動(dòng) allure 服務(wù):

          # 需要提前配置allure環(huán)境,才可以直接使用命令行
          allure serve ./report`

          最終,可以看到測(cè)試報(bào)告的效果圖如下:

          image.png
          來(lái)源:https://www.cnblogs.com/wintest


          -------- THE END --------

          ??

          瀏覽 83
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  男人的天堂资源网 | 中文字幕在线无码视频 | 黄色日批视频在线观看 | 久久久9久91精品夫妻电影 | 一区二区三区四区无码在线 |