整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          阿六帶你用python appium搭建app自動化測試環境

          我們在appium做app自動化測試,環境搭建是比較麻煩的。也是很多初學者在學習app自動化之時,花很多時間都難跨越的坎。今天小編就來講講appium如何搭建APP自動化測試環境。喜歡小編的可以給小編點點關注喲。

          沒有成功的環境,就沒有辦法繼續后續的使用。

          在app自動化測試當中,我們主要是通用電腦端的python代碼,能夠驅使手機端的app去進行操作。比如打開一個app,輸入用戶名和密碼,進入登陸操作。

          由于電腦端和手機端是兩個獨立的設備。要實現數據通信,就需要將二者連一起。因此對于真機用戶,需要用USB線連接手機和電腦,并且在開發者選項當中,開啟USB調試模式。

          app自動化環境安裝包括以下幾點:

          1、安裝node.js

          2、安裝appium desktop程序

          3、安裝JDK1.8及以上版本

          4、安裝安卓開發工具

          5、安裝appium python客戶端

          6、真機或者模擬器

          第一步:安裝nodejs和appium desktop程序

          nodejs官網下載地址:https://nodejs.org/en/download/

          appium的運行依賴于nodejs,所以要先安裝nodejs。nodejs下載完成之后,windows用戶雙擊安裝完成即可,不需要做額外配置。

          appium desktop下載官網:https://github.com/appium/appium-desktop/releases

          appium版本更新較快。最新的版本在你的電腦上不一定能運行起來。如果新版本運行不起來,那么建議換其它的版本。

          安裝也非常簡單,雙擊exe程序運行即可。

          第二步:安裝JDK

          JDK要求1.8版本以及以上。參考網上其它文章來安裝jdk。

          JDK下載地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

          第三步:安裝安卓開發工具

          自動化測試當中,會用到一些工具,但不會去開發一個app。所以sdk部分不需要。只需要下載工具部分即可。

          安卓sdk下載地址:http://tools.android-studio.org/index.php/sdk

          安裝步驟如下:

          1)解壓 platform-tools_r28.0.2-windows.zip到本地目錄

          2)雙擊SDKManager.exe

          3)在SDK Manager界面當中,只勾選:

          Tools當中的Android SDK Tools、Android SDK Platform-tools、Android SDK Build-tools

          Extras目錄。

          其它的一概不勾選。默認選中的請注意取消勾選!!!!

          打開SDK Manager,默認會選中安卓sdk,請一定要取消掉。

          4)配置環境變量:

          4.1 添加ANDROID_HOME環境變量,配置sdk根目錄。

          在以上的截圖中,

          ANDROID_HOME=D:\android-sdk-windows

          4.2 在PATH變量中添加三項內容:

          %ANDROID_HOME%\platform-tools

          %ANDROID_HOME%\tools

          %ANDROID_HOME%\build-tools.0.3

          檢測:

          進入cmd命令行,輸入adb version

          能夠正常顯示adb的版本就okay.


          第四步:安裝appium python客戶端

          使用python的pip命令,直接在線安裝:

          pip install Appium-Python-Client

          第五步:安裝模擬器(使用真機的用戶,可以跳過此步驟)

          本步驟中,選擇夜神模擬器。

          夜神模擬器官方網站下載地址:https://www.yeshen.com/

          下載安裝完成之后。桌面會有2個圖標:夜神模擬器、夜神多開器。

          夜神模擬器:默認安卓版本為4.4.2

          夜神多開器:可以增加安卓5.1模擬器、安卓7.1模擬器。

          在啟動模擬器之前,替換模擬器安裝路徑當中的nox_adb.exe

          第一步:將%ANDROID_HOME%\platform-tools目錄下的adb.exe拷貝到桌面,更改名稱為nox_adb.exe

          第二步:將第一步中的nox_adb拷貝到夜神模擬器安裝目錄下,替換原來的文件。

          再去啟動夜神模擬器。然后在cmd命令行當中,輸入命令:adb devices


          以上所有步驟安裝完成之后,恭喜你,環境搭建好了!可以開啟app自動化體驗之旅了!!

          喜歡的可以點贊關注小編喲!

          識Git版本控制

          自動化測試代碼反復執行,如果借用持續集成工具會提高測試效率,那么需要我們把自動化測試代碼發布到正式環境中,這時候用Git版本控制工具高效、穩定、便捷。

          分布式版本控制

          Git可以把代碼倉庫完整地鏡像下來,有完整的歷史記錄,它可以與遠端代碼庫進行交互。

          簡史

          Git誕生于2005年,速度快,極適合管理大項目。

          Git是什么

          其他版本控制系統如SVN,是隨時間變化的差異性文件比較,在某時間段某些文件進行更新。

          Git是快照流,存儲項目隨時間改變的快照,幾乎大部分操作都只需要訪問本地文件和資源。保證完整性,用哈希Hash,一般只添加數據,不刪除。

          Git三種狀態:

          已修改:在工作區修改文件,但沒保存到數據庫

          已暫存: 在暫存區對已修改的文件做標記,使其包含在下次提交的快照中

          已提交:在Git目錄安全地保存數據到本地數據庫

          基本Git工作流程:

          ①工作區修改文件;

          ②暫存區將下次提交的更改選擇性暫存,修改部分添加到暫存區;

          ③提交更新,找到暫存區的文件,將快照永久保存在Git目錄。

          命令行

          所有人都有命令行工具,會命令行則應該會GUI。

          安裝Git

          本次實踐安裝的最新版2.36.0,官網下載windows版本https://git-scm.com/download/win。

          初次運行Git前的配置

          1)設置用戶信息,以下命令:

          git config --global user.name “”

          git config --global user.email “”

          如果想給特定項目設置用戶信息,則在該項目目錄下運行無--global的命令。

          2)設置文本編輯器,如未配置,Git會使用操作系統自帶的編輯器。

          設置notepad++為文本編輯器:

          git config --global core.editor “’d:\dev\notepad++\notepad++.exe” -multiInst -notabbar -nosession -noPlugin”

          3)檢查配置信息:

          git config --list

          可逐項檢查,如:

          git config username

          獲得幫助

          git help +Verb,例如git help config。如果不用全面只需快速參考,使用命令git +Verb -h,例如git add -h。

          Git基礎

          獲取Git倉庫

          兩種獲得Git項目倉庫的方式:

          ①對尚未進行版本控制的本地目錄轉換為Git倉庫;

          ②從其他服務器克隆一個已存在的Git倉庫。

          (1)對已存在目錄中初始化倉庫

          如果有一個尚未進行版本控制的項目目錄,想要用Git控制它,那么需要進入該項目目錄中。

          在Windows上:

          cd c/user/my_project

          之后執行:

          git init

          該命令將創建名為.git的子目錄,這個子目錄含有你做初始化的Git倉庫中所有的必須文件,這些文件是Git倉庫的骨干。這時,我們僅僅是做了一個初始化的操作,你的項目里的文件還沒有被跟蹤。

          如圖所示:

          圖1

          圖2

          圖3

          如果在一個已存在文件的文件夾(非空文件夾)中進行版本控制,應該開始追蹤這些文件并進行初始提交。

          可以通過git add命令指定所需的文件進行追蹤,然后執行git commit:

          git add *.c

          git add LICENSE

          git commit -m ‘initial project version’

          如圖所示:

          圖4

          這樣已經得到了一個存在被追蹤文件與初始提交的Git倉庫。

          (2)克隆現有的倉庫

          如果想獲得一份已經存在了的Git倉庫的拷貝,比如說,想為某個開源項目貢獻自己的一份力,這時就要用到git clone命令。

          如果對其他VCS系統(比如Subversion)很熟悉,請留心以下所使用的命令是“clone”而不是“checkout”。這是Git區別于其他版本控制系統的一個重要特性,Git克隆的是該Git倉庫服務器上的幾乎所有數據,而不是僅僅復制完成你的工作所需要文件。

          當你執行git clone命令的時候,默認配置下遠程Git倉庫中的每一個文件的每個版本都將被拉取下來。實際上,如果服務器磁盤壞掉了,通常可以使用任何一個克隆下來的用戶端來重建服務器上的倉庫(雖然可能會丟失某些服務器端的hook設置,但是所有版本的數據仍在)。

          克隆倉庫的命令是git clone。比如,要克隆Git的自建項目HTMLTestRunner,可以用下面的命令:

          git clone https://github.com/mingming1205/HTMLTestRunner

          這會在當前目錄下創建一個名為“HTMLTestRunner”的目錄,并在這個目錄下初始化一個.git文件夾,從遠程倉庫拉取下所有數據放入.git文件夾,然后從中讀取最新版本的文件的拷貝。

          如果打開這個新建的HTMLTestRunner文件夾,會發現所有項目文件已經在里面了,準備就緒等待后續的開發和使用。

          如下圖:

          圖5

          圖6

          如果想在克隆遠程倉庫的時候,自定義本地倉庫的名字,可以通過額外的參數指定新的目錄名:

          git clone https://github.com/mingming1205/HTMLTestRunner myhtmltestrunner

          這會執行與上一條命令相同的操作,但是目標目錄名變成了myhtmltestrunner。

          如下圖:

          圖7

          圖8

          Git支持多種數據傳輸協議。以上的例子使用的是https://協議,不過也可以使用git://協議或者使用 SSH 傳輸協議,例如user@server:path/to/repo.git。

          至于所有這些協議在服務器端是如何配置使用,以及各種方式之間的利弊請查看“在服務器上搭建 Git”的介紹。

          記錄每次更新到倉庫

          執行命令:

          git commit -m “描述”

          查看提交歷史

          執行命令:

          git log

          如果附帶一系列總結的文字,執行命令:

          git log --stat

          如果限制日志查看數量,執行命令git log -p -2,當退出log時,在冒號“:”后面敲q即可。

          以下表格引自官網:

          感謝大家的閱讀,希望你們能從中有所收獲!

          最后:

          1)關注+私信回復:“測試”,可以免費領取一份10G軟件測試工程師面試寶典文檔資料。以及相對應的視頻學習教程免費分享!,其中包括了有基礎知識、Linux必備、Mysql數據庫、抓包工具、接口測試工具、測試進階-Python編程、Web自動化測試、APP自動化測試、接口自動化測試、測試高級持續集成、測試架構開發測試框架、性能測試等。

          2)關注+私信回復:"入群" 就可以邀請你進入軟件測試群學習交流~~

          今天我們來講講Pytest+Allure+Jenkins實現Web自動化集成測試,喜歡的小伙伴記得點贊喲。

          Pytest介紹

          pytest是一個非常成熟的全功能的Python測試框架,主要有以下幾個特點:簡單靈活、容易上手、文檔豐富;支持參數化,可以細粒度地控制被測用例;能夠支持簡單的單元測試和復雜的功能測試,還可以用來做Web自動化(selenium)、APP自動化(appium)以及接口自動化(pytest+requests);pytest具有很多第三方插件,并且可以自動以擴展,比較好用的如pytest-html(完美html測試報告生成)、pytest-rerunfailures(失敗用例重復執行)、pytest-xdist(多CPU分發)等;測試用例的skip和xfail處理;可以很好的和CI工具結合,如:Jenkins。

          Pytest安裝

          直接在命令窗口執行以下命令即可,更多信息可查閱官方文檔

          pip install pytest # 安裝pytest
          pytest --version   # 查看pytest版本

          直接在PyCharm中安裝,下面提到的使用pip安裝方式都可以直接在PyCharm中安裝,安裝成功后點擊【OK】

          PyCharm中設置使用pytest

          由于PyCharm默認使用Unitest,所以安裝pytest后需要更改默認值,配置路徑如下

          配置路徑:依次點擊【File】→【Settings】→【Tools】→【Python Integrated Tools】,【Default test runner】選擇“pytest”,然后點擊【Apply】→【OK】,就可以使用Pytest啦

          Pytest使用方法

          Pytest規則

          編寫pytest測試用例默認使用以下規則,當然,規則是可以修改的

          • 測試文件以test_開頭或者以_test結尾
          • 測試類以Test開頭,且類中不能包含__init__方法
          • 測試函數/方法以test_開頭
          • 斷言使用基本的assert即可

          修改規則需添加配置文件pytest.ini,它是pytest的主配置文件,可以修改pytest的默認行為,此文件放在項目的根目錄下才會生效(除非指定目錄查找配置文件),如下配置,注意:實際配置文件中不可出現中文、冒號、引號等

          [pytest]
          python_files = test_*.py *_test.py case_*	# 添加以case_*開頭的測試模塊
          python_classes = Test* *_case* 				# 添加以*_case結尾的測試類
          python_functions = test_* case_* 			# 添加以case_*開頭的測試函數
          testpaths = testcases	# 指定測試目錄,是指以testpaths所在目錄為基準的相對路徑
          addopts = -vs -l		# 將常用命令參數設為默認,省去重復輸入的工作
          norecursedirs = .* build dist CVS _darcs {arch} *.egg src # 指定pytest忽略查找某些目錄,多個目錄之間空格隔開
          log_cli = True			# 控制臺實時輸出日志
          
          # 注冊mark標記
          markers =
          	smoke : smoke tests as smoke
              output : print

          Pytest標記

          上面的配置文件中提到了標記,又如何使用呢?

          默認情況下,pytest會遞歸查找當前目錄下所有以test開頭或結尾的Python腳本,并執行文件內所有以test開頭的函數和方法。工作中由于功能尚未實現、挑選用例執行冒煙測試等原因,只想測試指定用例,在pytest中有幾種方法可解決

          1. 顯式指定函數名,通過::標記,例如:某文件內存在兩個類,但一個類尚未完成,只想執行第二個類中的用例,就可指定類執行
          2. pytest -vs test_learn.py::Testpy2 # 只執行文件中的Testpy2類 pytest -vs test_learn.py::Testpy2::test_method # 只執行文件中Testpy2類下的test_method方法
          3. 使用模糊匹配,通過-k參數識別關鍵字,例如:
          4. pytest -k login test_learn.py # 只執行文件中包含關鍵字login的用例
          5. 使用pytest.mark在用例上進行標記,標記需要在pytest.ini文件中配置,配置方法見上文,格式一定要寫對,若未配置也可執行,但是會出現警告,配置中冒號前是標記名,冒號后可以理解為標記解釋,當然也可以前后一樣
          6. @pytest.mark.check # 在函數上設置標記 def test_func1(self): assert 1 == 1 @pytest.mark.output # 在類上面設置標記,對類中所有方法都有效 class caseCls(object): def dyd_case(self): @pytest.mark.smoke def test_func1(self): # 在類中的方法上設置標記 print("這是Pytest")
          7. 執行帶有標記的函數,使用-m參數
          8. pytest -m check test_learn.py # 執行帶有check標記的用例,此標記在一個函數上標記了一次,所有只會執行一條用例 pytest -m smoke test_learn.py # 執行帶有smoke標記的用例,此標記在一個方法上標記了一次,同樣只會執行一條用例 pytest -m output test_learn.py # 執行帶有output標記的用例,因為用例在類上,故類中所有的用例都會被執行

          Pytest運行

          1. 通過命令行運行
          2. pytest -vs /package_name # 執行包中所有模塊的用例 pytest -vs file_name.py # 執行單獨的pytest模塊,file_name.py文件 pytest -vs file_name.py::class_name # 只執行文件中的class_name類 pytest -vs file_name.py::class_name::method_name # 只執行文件中class_name類下的method_name方法 pytest -vs file_name.py::function_name # 只執行文件中function_name函數
          3. pytest命令參數
          • -v 展示每個測試函數的執行結果(詳細信息)
          • -q 只顯示整體測試結果(簡要信息)
          • -s 展示測試函數中print()函數輸出信息
          • -k 只執行包含關鍵字的用例
          • -m 只執行指定標記的用例
          • -x 出現失敗用例則立即停止執行
          • -l 用例失敗時打印相關局部變量
          • -c 從指定目錄加載配置文件,而非自動查找配置文件
          • -lf 只執行上次失敗的用例,若沒有則執行全部用例
          • -ff 先執行完上次失敗的再執行剩余的用例
          • -tb=style 用例失敗時錯誤的詳細程度(auto/long/short/line/native/no)
          • --maxfail=num 用例允許失敗的最大次數,超出則立即停止執行
          • --collect-only 收集但不執行用例
          • --durations=num -vv 顯示設定數值內,按照耗時時長降序打印結果,通常用于調優
          • -h--help 幫助
          • 通過main方法
          • if __name__ == '__main__': pytest.main(["-sv", "file_name.py"]) # 通過main函數執行

          示例:

          # 文件名稱命名規則,以test_開頭或_test結尾
          import pytest
          def test_func():	# 通常在類外面稱為函數,函數命名規則,以test_開頭
              assert 1 == 1
          class Testpy(object):		# 類命名規則,以Test開頭
              def test_method(self):	# 通常在類中稱為方法,方法命名規則與函數一樣,以test_開頭
                  assert 1 + 2 == 3
              @pytest.mark.smoke
              def test_func1(self):
                  print("這是Pytest")
          @pytest.mark.smoke
          class caseCls(object):
              def dyd_case(self):
                  print("修改函數后的規則后")
          if __name__ == '__main__':
              pytest.main(["test_learn.py"])	# 通過main函數執行命令

          使用命令執行示例中的用例

          pytest ../Pytest								# 執行包中所有模塊的用例
          pytest -vs test_learn.py						# 執行單獨的pytest模塊,test_learn.py文件
          pytest -vs test_learn.py::Testpy				# 只執行文件中的Testpy類
          pytest -vs test_learn.py::Testpy::test_method	# 只執行文件中Testpy類下的test_method方法
          pytest -vs test_learn.py::test_function			# 只執行文件中test_function函數
          pytest -m smoke test_learn.py					# 執行帶有smoke標記的用例
          pytest -k dyd test_learn.py						# 只執行包含關鍵字dyd的用例
          pytest --maxfail=2 test_learn.py				# 執行指定文件中的用例,失敗用例超出2條則停止執行
          pytest --collect-only test_learn.py				# 收集指定文件中的用例,不加文件名則直接搜索當前目錄下所有用例



          Pytest參數化

          在pytest中,可以使用參數化測試,即每組參數都獨立執行一次

          使用參數化裝飾器pytest.mark.parametrize(argnames,argvalues),參數化的名字要與方法中的參數名一一對應,傳遞多個參數時可使用列表、元組、字典或列表嵌套等,實際工作中還是以json、yaml、excel等文件形式做參數化的較多,后續再介紹,示例如下:

          import pytest # 導入pytest包
          
          list = [1,"1+1","1+2"] # 列表
          # ↓參數必須與值的個數相等,可使用ids參數重命名,名字方便理解其意思即可,ids的個數要等于傳遞的數據個數
          @pytest.mark.parametrize("value",list,ids=["value=1","value=2","value=3"])
          def test_list(value):
              print(value)	# 打印三個結果
          
          tuple = [("abc"),("def"),["g","h","i"],[1,2,3]] # 元組
          @pytest.mark.parametrize("x,y,z",tuple)  # 參數必須與值的個數相等
          def test_xzy(x,y,z):
              print(x,y,z)	# 打印四個結果
          
          @pytest.mark.parametrize("input,expect",[("1+1",2),("2+2",4)]) 
          def test_count(input,expect):
              assert eval(input) ==expect # 估算實際結果是否與期望結果一致,打印兩個結果
          
          dict = ({"username":"dyd","passwd":123456},{"phone":18888888888,"age":18}) # 字典
          @pytest.mark.parametrize("dic",dict)
          def test_dict(dic):
              print(dic)	# 打印兩個結果
          
          data = [ # ↓通過pytest中的param定義參數,id是對參數的一個說明,可自定義,方便理解各用例的含義即可
              pytest.param(100,100,200,id="a+b:pass"),
              pytest.param("a","b","ab",id="a+b:pass"),
              pytest.param(1,1,6,id="a+b:fail")]
          def add(a,b): # 定義一個add相加的函數
              return a+b
          class TestParam(object):
              @pytest.mark.parametrize("a,b,expect",data)
              def test_param(self,a,b,expect):
                  assert add(a,b) == expect # 調用a+b,判斷實際結果是否與期望結果一致,出現三個結果
          
          @pytest.mark.parametrize("x",(1,2,3))
          @pytest.mark.parametrize("y",(4,5,6))
          def test_dkej(x,y):
              print(f"打印組合方式:({x},{y})") # 通過參數化實現笛卡爾積

          Setup與teardown

          在執行用例時,可能某些操作只需要進行一次,比如打開瀏覽器,或者每次操作前都需要先執行其它操作,比如查看數據前需要連接數據庫,查看后需要斷開數據庫等,類似的操作可以使用以下幾種setup/teardown進行配置與銷毀

          • 模塊級 setup_module/teardowm_module 開始于模塊始末,全局的
          • 函數級 setup_function/teardown_function 只對函數用例生效(在類外)
          • 類級 setup_class/teardown_class 只在類中前后運行一次(在類中)
          • 方法級 setup_method/teardown_method 類中的每個方法執行前后(在類中)
          • 類中的 setup/teardown 運行在調用方法前后(常用)

          下面是使用方法簡單示例,setup/teardown并非必須成對使用,比如連接數據庫后不想斷開,就可以只使用setup

          def setup_module():
              print("setup_模塊級")
          def teardown_module():
              print("teardown_模塊級")
          …… setup_function/teardown_function
          def test_01():
              print("測試01")
          def test_02():
              print("測試02")
          
          class Testcase01(object):
              @classmethod
              def setup_class(cls):
                  print("setup_類")
              def teardown_class(cls):
                  print("teardown_類")
                  …… setup_method/teardown_method
                  …… setup/teardown
              def test_03(self):
                  print("測試03")
              def test_04(self):
                  print("測試04")

          下面是兩個函數test_01、02和兩個方法test_03、04,在配置setup和teardown后運行的結果,從結果中可以看出它們的層級關系

          setear_test.py::test_01 
          setup_模塊級
          setup_函數
          測試用例01	PASSED
          teardown_函數
          
          setear_test.py::test_02 
          setup_函數
          測試用例02	PASSED
          teardown_函數
          
          setear_test.py::Testcase01::test_03 
          setup_類
          setup_方法
          setup
          測試用例03	PASSED
          teardown
          teardown_方法
          
          setear_test.py::Testcase01::test_04 
          setup_方法
          setup
          測試用例04	PASSED
          teardown
          teardown_方法
          teardown_類
          teardown_模塊級

          Pytest fixture

          上面setup/teardown可實現的功能,fixture可以更靈活的實現

          定義fixture和定義普通函數差不多,唯一區別是在函數上加上個裝飾器@pytest.fixture()

          為了跟用例有所區分,fixture命名時不要以test開頭,fixture是有返回值的,若沒有返回值則默認為None

          用例調用fixture的返回值,直接把fixture的函數名當作變量名

          import pytest
          @pytest.fixture()				# 默認范圍為函數級(function)
          def login():
              print("請先登錄")
              return
          def test_Search():				# 不需要登錄,所以不調用fixture
              print("搜索商品,無需登錄")
          def test_Cart(login):			# 需要登錄,調用fixture
              print("加購商品,需登錄")
          
          @pytest.fixture(scope="class")	# 設置范圍為類級(class)
          def login():
              print("請登錄后再購買")
              return
          class Testfix(object):
              def test_Look(self):
                  print("查看商品,無需登錄")	# 不需要登錄,所以不調用fixture
              def test_Pay(self,login):
                  print("購買商品,需登錄")	# 需要登錄,調用fixture

          輸出結果如下,控制范圍(scope)還有module,package,session,以及其它參數如:param、ids、name等

          test_fix.py::test_Search 
          搜索商品,無需登錄	PASSED
          test_fix.py::test_Cart
          請登錄后再購買
          加購商品,需登錄	PASSED
          
          test_fix.py::Testfix::test_Look
          查看商品,無需登錄	PASSED
          test_fix.py::Testfix::test_Pay 
          請登錄后再購買
          購買商品,需登錄	PASSED

          再介紹一下session級別,它是可以跨.py模塊調用的,也就是說有多個.py文件的測試用例時,只需調用一次fixture,設置scope="session",并寫在conftest.py文件中,conftest.py文件是固定名稱,pytest會自動識別此文件,所以不可改名稱,此文件放在項目根目錄,則可全局調用,放在某個包中,則只對包內的有效

          比如使用鉤子函數實現失敗用例截圖,將以下代碼寫在conftest.py中,其它模塊就可以直接調用

          import allure
          import pytest
          from selenium import webdriver
          
          driver = None # 自定義一個driver=None
          @pytest.hookimpl(tryfirst=1,hookwrapper=1)
          def pytest_runtest_makereport(item,call):   # 鉤子函數
              # 用例執行完成后再執行此操作,(后置處理用yield)
              outcome = yield # 測試用例執行完后接下來要做什么事情
              rep = outcome.get_result() # 獲取用例執行完成之后的結果
              if rep.when == "call" and rep.failed:   # 若結果正在被調用而且是失敗的則進行截圖
                  img = driver.get_screenshot_as_png()  # 若出現異常,則進行截圖操作
                  allure.attach(img, "失敗截圖", allure.attachment_type.PNG)  # 將圖片展現在Allure報告上
          
          # 自定義一個Fixture,初始化driver對象
          @pytest.fixture(scope="session",autouse=True)
          def init_driver():
              global driver
              driver = webdriver.Chrome()
              return driver  # 返回初始化后的driver,就可以直接被調用啦



          調用conftest.py中的函數

          def test_baidu(init_driver):
              init_driver.get("http://baidu.com")
              init_driver.find_element(By.CLASS_NAME, "123").click()
              ……

          Pytest Allure

          Allure安裝

          Allure運行需要Java環境,Java安裝并配置環境變量后,在命令窗口執行以下命令,更多信息可查閱官方文檔

          pip install allure-pytest

          安裝完成后,下載一個allure可執行文件,點擊此次進入下載列表頁,下載所需版本,下載后解壓文件,然后將bin目錄加到PATH環境變量中,最后在命令行窗口輸入allure或者allure --version驗證是否配置成功

          Allure用例描述

          添加裝飾器

          參數值

          參數說明

          @allure.epic()

          epic描述

          定義項目,往下是feature

          @allure.feature()

          模塊名稱

          大的功能點描述,往下是story

          @allure.story()

          次級分類

          用戶故事,次級功能點描述,往下是title

          @allure.title()

          用例的標題

          測試用例重命名

          @allure.testcase()

          測試用例的鏈接地址

          對應功能測試用例系統里面的用例

          @allure.issue()

          測試用例的缺陷地址

          對應缺陷管理系統里面的鏈接

          @allure.description()

          用例描述

          測試用例的描述

          @allure.step()

          操作步驟

          測試用例的步驟

          @allure.severity()

          用例等級

          blocker,critical,normal,minor,trivial

          @allure.link()

          鏈接

          定義一個鏈接,在測試報告展現

          @allure.attach()

          附件

          報告添加附件,支持html、圖片、視頻

          Allure報告生成

          生成測試報告必須在命令行執行

          1. 生成中間結果,使用下面的命令指定結果生成到的目錄,生成結果中包含兩個格式文件(text、json)
          2. pytest --alluredir=./result --clean-alluredir # 將包中所有模塊的用例生成報告并清除之前的報告 pytest --alluredir=./result test_Jpress.py # 將指定的文件生成報告 pytest --alluredir=./result test_Jpress.py::TestUser# 將指定文件中的類生成報告 …… # 可以指定方法或使用標記等生成報告
          3. 中間結果無法直接查看,執行下面命令啟動Allure查看HTML報告
          4. allure serve ./result
          5. 也可以直接生成可在線訪問的HTML結果
          6. allure generate ./result -o ./report --clean-alluredir # 可以加上--clean-alluredir參數,表示若指定目錄已存在則先清空此目錄 # 也可以加上--allure-no-capture,表示無需將pytest捕獲的日志記錄(logging)、標準輸出(stdout)、標準錯誤(stderr)附加到報告中

          示例如下:

          from selenium import webdriver
          from selenium.webdriver.common.by import By
          from selenium.webdriver.support import expected_conditions as EC
          from selenium.webdriver.support.wait import WebDriverWait
          import pytest
          import allure
          from util import util   # 導入自己封裝的日志模塊
          
          loginError = [["","654321","賬號不能為空"],["test","123456","用戶名不正確。"],
                        ["admin","","密碼不能為空"],["admin","654321","用戶名或密碼不正確"]]
          loginOK = [["admin","123456","用戶中心"]]
          
          @allure.feature("Jpress后端測試")
          class TestUser(object):
              def setup_class(self):
                  self.driver = webdriver.Chrome()
                  self.driver.maximize_window()
                  self.driver.get("http://192.166.66.22:8080/user/login")
                  self.logger = util.get_logger()
                  self.logger.info("登錄測試")
          
              @allure.story("這是登錄失敗的測試用例")
              @allure.description("登錄平臺-錯誤場景")
              @pytest.mark.parametrize("username,pwd,expected",loginError)
              def test_user_login_Error(self,username,pwd,expected):
                  user = username
                  pwd = pwd
                  expected = expected
          
                  # 清空輸入框后輸入用戶名
                  self.driver.find_element(By.NAME, "user").clear()
                  self.driver.find_element(By.NAME, "user").send_keys(user)
                  # 清空輸入框后輸入密碼
                  self.driver.find_element(By.NAME, "pwd").clear()
                  self.driver.find_element(By.NAME, "pwd").send_keys(pwd)
                  # 點擊【登錄】
                  self.driver.find_element(By.CLASS_NAME, "btn").click()
                  WebDriverWait(self.driver, 3).until(EC.alert_is_present())
                  alert = self.driver.switch_to.alert
                  # 驗證報錯信息是否正確
                  assert alert.text == expected
                  self.logger.debug("登錄失敗,用戶名或密碼輸出有誤!")
                  alert.accept()
          
              @allure.story("后臺管理平臺登錄失敗")
              @allure.description("記錄失敗時的截圖和日志")
              def test_failcase(self):
                  self.driver = webdriver.Chrome()
                  self.driver.get("http://192.166.66.22:8080/admin/login")
                  self.driver.find_element(By.NAME, "user").send_keys("admin")
                  self.driver.find_element(By.NAME, "pwd").send_keys("123456")
                  self.driver.find_element(By.NAME, "captcha").send_keys(8888)
                  try:
                      self.driver.find_element(By.CLASS_NAME, "btn錯誤的登錄按鈕元素").click()
                  except Exception as e:
                      img = self.driver.get_screenshot_as_png()   # 若出現異常,則進行截圖操作
                      allure.attach(img, "失敗截圖", allure.attachment_type.PNG)  # 將圖片展示在Allure報告上
                      log = self.logger.error("報錯信息:%s", "無法登錄,找不到登錄按鈕", exc_info=1)  # 記錄報錯日志
                      # 獲取報錯日志,并將日志展示在Allure報告上
                      allure.attach.file(self.driver.get_log(log), "失敗日志", allure.attachment_type.TEXT)
                  WebDriverWait(self.driver, 3).until(EC.alert_is_present())
                  alert = self.driver.switch_to.alert
                  assert alert.text == "登錄失敗"
          
              @allure.story("這是登錄成功用例")
              @allure.description("成功登錄至平臺")
              @allure.severity(severity_level="Blocker")
              @pytest.mark.parametrize("username,pwd,expected",loginOK)
              def test_user_login_OK(self,username,pwd,expected):
                  user = username
                  pwd = pwd
                  expected = expected
          
                  self.driver.find_element(By.NAME, "user").clear()
                  self.driver.find_element(By.NAME, "user").send_keys(user)
                  self.driver.find_element(By.NAME, "pwd").clear()
                  self.driver.find_element(By.NAME, "pwd").send_keys(pwd)
                  self.driver.find_element(By.CLASS_NAME, "btn").click()
                  WebDriverWait(self.driver, 3).until(EC.title_is(expected))
                  assert self.driver.title == expected
          
              @allure.story("文章管理測試用例")
              @allure.title("查看文章列表")
              @allure.step("步驟1:進入文章列表")
              def test_article_list(self):
                  expected = "http://192.166.66.22:8080/ucenter/article"
                  self.driver.find_element(By.XPATH,'//span[contains(text(),"我的文章")]').click()
                  self.driver.find_element(By.LINK_TEXT,"文章列表").click()
                  WebDriverWait(self.driver, 2).until(EC.url_contains("/ucenter/article"))
                  assert self.driver.current_url == expected
          
              @allure.story("文章管理測試用例")
              @allure.title("查看文章詳情")
              @allure.step("步驟2:查看文章詳情")
              @allure.severity(severity_level="critical")
              def test_Look_article(self):
                  expected = "一個小測試"
                  handle = self.driver.current_window_handle  # 獲取當前窗口句柄
                  self.driver.find_element(By.LINK_TEXT, "一個小測試").click()
                  handles = self.driver.window_handles  # 獲取所有窗口句柄
                  for newhandle in handles:  # 對窗口進行遍歷
                      if newhandle != handle:  # 判斷當前窗口是否為新窗口
                          self.driver.switch_to.window(newhandle)  # 切換到新打開的窗口
                  WebDriverWait(self.driver, 2).until(EC.title_is(expected))
                  assert self.driver.title == expected
                  # 關閉瀏覽器
                  self.driver.quit()
          
          @allure.feature("Jpress前端測試")
          class TestBlog(object):
              def setup_class(self):
                  self.driver = webdriver.Chrome()
                  self.driver.maximize_window()
                  self.driver.get("http://192.166.66.22:8080/")
                  self.logger = util.get_logger()
                  self.logger.info("博客訪問測試")
          
              @allure.title("查看博客詳情")
              @pytest.mark.skipif(reason="刻意跳過此用例")
              def test_details(self):
                  expected = "一個小測試"
                  self.driver.find_element(By.CLASS_NAME,"bh-card-main-title").click()
                  WebDriverWait(self.driver, 2).until(EC.url_contains("/article/2"))
                  assert self.driver.title == expected
                  # 關閉瀏覽器
                  self.driver.quit()



          下圖是生成的Allure報告用例執行結果

          數據驅動測試(DDT)

          讀取excel文件

          需要安裝xlrd模塊,使用xlrd模塊處理excel文件,新版xlrd不支持xlsx格式的excel,會報錯xlrd.biffh.XLRDError: Excel xlsx file; not supported,可以使用xls格式的excel,或者可以安裝老版本的xlrd

          pip install xlrd==1.2.0	# 此版本支持xlx格式的excel

          結合pytest的參數化的方式,實現excel文件數據驅動,示例如下:

          import pytest
          import xlrd
          
          def get_data(): # 定義一個獲取數據的函數
              filename = "my_data.xlsx" # 定義數據文件
              wb = xlrd.open_workbook(filename)   # 打開文件
              sheet = wb.sheet_by_index(0)    # 使用索引方式獲得文件中的第一個sheet
              rows = sheet.nrows  # 獲取行
              cols = sheet.ncols  # 獲取列
              lst = []
              for row in range(rows): # 遍歷行
                  for col in range(cols): # 遍歷列
                      cell_data = sheet.cell_value(row,col)   # 獲取單元格中的數據
                      lst.append([cell_data])   # 將單元格中的數添加到列表中
              return lst  # 返回list列表
          
          @pytest.mark.parametrize("value",get_data())    # 調用excel數據
          def test_read(value):
              print(value)
              # 輸出結果,2*2的表格,打印每個單元格中的數據
          test_excel.py::test_read[value0] PASSED                                  [ 25%]['xlsx']
          test_excel.py::test_read[value1] PASSED                                  [ 50%]['格式']
          test_excel.py::test_read[value2] PASSED                                  [ 75%]['讀取文件']
          test_excel.py::test_read[value3] PASSED                                  [100%]['666']

          讀取csv文件

          csv文件是使用逗號分隔的文本文件,直接使用python的csv模塊處理csv文件,然后結合pytest的參數化的方式,實現csv文件數據驅動,

          示例如下:

          # 測,試
          # ceshi,testing
          import csv
          import pytest
          
          def get_data():
              with open("my_data.csv","r",encoding='UTF-8') as j:    # 只讀模式打開csv文件
                  data = csv.reader(j)    # csv.reader(f)返回一個csv_reader對象
                  lst = []
                  for row in data: # 遍歷對象,每次返回一行
                      lst.extend(row)   # 將數據一次性追加到lst中,將結果寫到一個列表中
                  return lst  # 返回lst
          
          @pytest.mark.parametrize("csv_value",get_data())    # 調用csv數據
          def test_read(csv_value):
              print(csv_value)    # 將寫在列表中的數據一個一個的輸出
              # 輸出結果
          test_csv.py::test_read[\u6d4b] PASSED                                    [ 25%]測
          test_csv.py::test_read[\u8bd5] PASSED                                    [ 50%]試
          test_csv.py::test_read[ceshi] PASSED                                     [ 75%]ceshi
          test_csv.py::test_read[testing] PASSED                                   [100%]testing

          讀取json文件

          直接使用python中的json模塊處理json文件,然后結合pytest的參數化方式,實現json文件數據驅動

          json文件內容

          [
              {
                  "name":"",
                  "pwd":"654321",
                  "expected":"賬號不能為空"
              },
              {
                  "name":"admin",
                  "pwd":"",
                  "expected":"密碼不能為空"
              },
              {
                  "name":"admin",
                  "pwd":"654321",
                  "expected":"用戶名或密碼不正確"
              }
          ]

          示例如下:

          import pytest
          import json
          from selenium import webdriver
          from selenium.webdriver.common.by import By
          from selenium.webdriver.support.wait import WebDriverWait
          from selenium.webdriver.support import expected_conditions as EC
          
          def get_data():
              lst = []
              with open("my_data.json","r",encoding='UTF-8') as j:    # 只讀模式打開json文件
                  dict_data = json.loads(j.read())    # 將json轉換為字典
                  for i in dict_data: # 遍歷字典
                      lst.append(tuple(i.values()))   #將數據以元組形式添加到lst中
              return lst  # 返回lst
          
          #	此時輸出get_data()值,會得到的下面結果
          [('', '654321', '賬號不能為空'), ('admin', '', '密碼不能為空'), ('admin', '654321', '用戶名或密碼不正確')]
          
          class TestUser(object):
              def setup_class(self):
                  self.driver = webdriver.Chrome()
                  self.driver.maximize_window()
                  self.driver.get("http://192.166.66.22:8080/user/login")
          
              @pytest.mark.parametrize("username,pwd,expected",get_data())    # 調用json數據
              def test_user_login_Error(self,username,pwd,expected):
                  user = username
                  pwd = pwd
                  expected = expected
          
                  # 清空輸入框后輸入用戶名
                  self.driver.find_element(By.NAME, "user").clear()
                  self.driver.find_element(By.NAME, "user").send_keys(user)
                  # 清空輸入框后輸入密碼
                  self.driver.find_element(By.NAME, "pwd").clear()
                  self.driver.find_element(By.NAME, "pwd").send_keys(pwd)
                  # 點擊【登錄】
                  self.driver.find_element(By.CLASS_NAME, "btn").click()
                  # 等待頁面加載
                  WebDriverWait(self.driver, 3).until(EC.alert_is_present())
                  alert = self.driver.switch_to.alert
                  # 驗證報錯信息是否正確
                  assert alert.text == expected
                  alert.accept()

          讀取yaml文件

          先安裝yaml模塊,然后結合pytest的參數化方式,實現yaml文件數據驅動,和json差不多

          pip install pyyaml

          yaml文件內容

          ---
          name: ""
          pwd: "123456"
          expected: "賬號不能為空"
          ---
          name: "admin"
          pwd: ""
          expected: "密碼不能為空"
          ---
          name: "admin"
          pwd: "654321"
          expected: "用戶名或密碼不正確"

          使用yaml驗證登錄,示例如下:

          import pytest
          import yaml
          from selenium import webdriver
          from selenium.webdriver.common.by import By
          from selenium.webdriver.support.wait import WebDriverWait
          from selenium.webdriver.support import expected_conditions as EC
          
          def get_data():
              lst = []
              with open("my_data.yaml","r",encoding='UTF-8') as j:    # 只讀模式打開yaml文件
                  ym = yaml.load_all(j.read()) # 使用load_all生成迭代器
                  for i in ym: # 遍歷ym中的數據
                      lst.append(tuple(i.values()))   #將數據以元組形式添加到lst中
              return lst  # 返回lst
          
          #	此時輸出get_data()值,會得到和讀取json文件一樣的結果
          [('', '123456', '賬號不能為空'), ('admin', '', '密碼不能為空'), ('admin', '654321', '用戶名或密碼不正確')]
          
          class TestUser(object):
              def setup_class(self):
                  self.driver = webdriver.Chrome()
                  self.driver.maximize_window()
                  self.driver.get("http://192.166.66.22:8080/user/login")
          
              @pytest.mark.parametrize("username,pwd,expected",get_data())    # 調用yaml數據
              def test_user_login_Error(self,username,pwd,expected):
                  user = username
                  pwd = pwd
                  expected = expected
          
                  # 清空輸入框后輸入用戶名
                  self.driver.find_element(By.NAME, "user").clear()
                  self.driver.find_element(By.NAME, "user").send_keys(user)
                  # 清空輸入框后輸入密碼
                  self.driver.find_element(By.NAME, "pwd").clear()
                  self.driver.find_element(By.NAME, "pwd").send_keys(pwd)
                  # 點擊【登錄】
                  self.driver.find_element(By.CLASS_NAME, "btn").click()
                  # 等待頁面加載
                  WebDriverWait(self.driver, 3).until(EC.alert_is_present())
                  alert = self.driver.switch_to.alert
                  # 驗證報錯信息是否正確
                  assert alert.text == expected
                  alert.accept()

          Jenkins集成Allure報告

          本次Jenkins是安裝在Windows上的,直接Jenkins官網下載安裝包進行安裝就行啦,不多做介紹

          1. Jenkins安裝完成后,進入插件管理,安裝Allure插件


          2.進入全局配置,配置Allure Commandline,填寫本地Allure安裝路徑,別名自定義,完成后點擊【應用】→【保存】

          3.新建一個自由風格的項目

          4.配置項目,在常規配置里點擊【高級】,勾選“使用自定義的工作空間”,填寫工作空間目錄(通常填寫項目的主目錄),顯示名稱自定義

          然后增加構建步驟,選擇“執行windows批處理命令”,填寫要執行的命令,命令可以指定文件或類等,具體上文有介紹

          pytest -vs --alluredir=./pytest_result test_Jpress.py --clean-alluredir

          最后增加構建后操作步驟,選擇“Allure Report”,填寫結果路徑,一定要與構建時的路徑相同,然后【應用】→【保存】

          8.在Jenkins頁面上會出現Allure報告標識,點擊可查看具體構建報告

          報告結果如下圖所示

          好了今天的分享就到這了,喜歡的記得關注點贊喲


          主站蜘蛛池模板: 亚洲成在人天堂一区二区| 精品不卡一区中文字幕 | 精品国产高清自在线一区二区三区| 无码夜色一区二区三区| 在线电影一区二区| 一区二区三区高清| 久久精品一区二区东京热| 一区二区三区无码高清| 久久久精品人妻一区二区三区 | 中文字幕av无码一区二区三区电影 | 国产伦精品一区二区免费| 无码人妻精品一区二区三区99仓本 | 夜色阁亚洲一区二区三区| 极品少妇一区二区三区四区| 亚洲国产情侣一区二区三区| 鲁丝片一区二区三区免费| 色婷婷AV一区二区三区浪潮| 一区二区三区免费在线视频| 无码人妻久久一区二区三区蜜桃 | 国产一区二区在线|播放| 伊人无码精品久久一区二区| 伊人色综合视频一区二区三区| 亚洲一区无码中文字幕| 国产观看精品一区二区三区 | 亚洲国产成人精品久久久国产成人一区二区三区综 | 国产精品综合AV一区二区国产馆| 一区二区三区日韩| 无码国产精品久久一区免费| 日本国产一区二区三区在线观看| 亚洲国产欧美国产综合一区| 视频一区二区精品的福利| 国产一区二区三区在线2021 | 又紧又大又爽精品一区二区| 国产成人无码AV一区二区在线观看| 亚洲综合色一区二区三区| 日韩人妻无码一区二区三区99| 福利片免费一区二区三区| 丰满岳妇乱一区二区三区| 亚洲毛片αv无线播放一区| 香蕉久久一区二区不卡无毒影院| 精品亚洲av无码一区二区柚蜜|