appium+pytest+allure+jenkins 如何實現多台手機連接


使用appium可以實現app自動化測試,我們之前是連接一台手機去運行,如何同時連接多台手機呢?很多人可能想到的是多線程(threading)。今天分享一種比多線程更簡單的方法,雖然不是多台手機同時運行,但可以連接多台手機依次運行,大致的運行方式是:001號測試用例:A手機,B手機...,002號測試用例:A手機,B手機...

環境准備

  • appium的安裝:adt,nodejs,appium的python庫,appium server
  • pytest的安裝:pytest
  • allure的安裝:allure的python庫pytest-allure-adaptor
    jenkins上插件的安裝-傳送門
  • jenkins的安裝:windows上的安裝-傳送門
  • 手機/模擬器:華為榮耀暢玩5C,夜神模擬器

框架改造

1. 配置改寫

以上課所寫的前程貸的自動化框架為主,框架的分層如下(框架分享 - 傳送門:提取碼: zvry):

在上述框架中,我們的配置信息存在Caps目錄下的Caps.yaml中,譬如這樣

-
  platformName: Android
  platformVersion: 5.1.1
  deviceName: JTG6T16307007427
  appPackage: com.xxzb.fenwoo
  appActivity: .activity.addition.WelcomeActivity
  noReset: True

-
  server_ip: 127.0.0.1
  server_port: 4723

這只是一台手機的設備信息和連接信息,如果我們需要兩台甚至多台,就需要把它們的信息都寫入yaml文件,每個手機的信息用一個列表描述

-
  deviceDesc: Honor_5C
  server_url: 127.0.0.1
  server_port: 4723
  desired_caps:
    platformName: Android
    platformVersion: 5.1.1
    deviceName: JTG6T16307007427
    udid: JTG6T16307007427
    appPackage: com.xxzb.fenwoo
    appActivity: .activity.addition.WelcomeActivity
    noReset: True

-
  deviceDesc: YeShen
  server_url: 127.0.0.1
  server_port: 4726
  desired_caps:
    platformName: Android
    platformVersion: 5.1.1
    deviceName: 127.0.0.1:62025
    udid: 127.0.0.1:62025
    appPackage: com.xxzb.fenwoo
    appActivity: .activity.addition.WelcomeActivity
    noReset: True

注意:

  1. 上述yaml文件中多了deviceDesc和udid,前者是我們用來區分不同的手機,后者是appium用來區分不同的手機  2) 給不同的手機設置不同的端口,榮耀暢玩5C使用的是4723,夜神模擬器使用的是4726

2. BaseDriver的改寫

BaseDriver是公共的driver類,通過讀取yaml配置信息,生成並返回driver對象,其基本的傳遞路徑是:Caps.yaml-->BaseDriver.py-->conftest:設置不同的fixture,返回driver,因此它是溝通配置信息和conftest的橋梁,既然配置信息變了,相應的BaseDriver的讀取也要改變
改寫前的BaseDriver.py,具體代碼如下:

import yaml
import os
from Common.dir_config import caps_dir
from appium import webdriver

class BaseDriver:

    def base_driver(self, automationName="appium", noRest=True):
        fs = open(os.path.join(caps_dir, "caps.yaml"))
        datas = yaml.load(fs)
        #通過判斷automationName,來決定是否添加uiautomator2
        if automationName != "appium":
            datas[0]["automationName"] = automationName
        if noRest == False:
            datas[0]["noReset"] = False
        #連接appium server,並告訴其要操作的對象
        server = 'http://{0}:{1}/wd/hub'.format(datas[1]["server_ip"], datas[1]["server_port"])
        driver = webdriver.Remote(server, datas[0])
        return driver

由於是多台手機,每個手機的通過配置信息里的deviceDesc來區分,BaseDriver類中的base_driver函數需要設置一個變量device來區別不同的手機,這個device是我們傳入的,如果我們傳入的是device="YeShen",還是用之前的代碼的話,得到將是全部的信息。有必要通過if判斷篩選下,只取對應device的配置信息

import yaml
from appium import webdriver

class BaseDriver:


    def base_driver(self, device, automationName="appium", noReset=True):
        fs = open(r"D:\Program\Jenkins\workspace\APP_AutoTest\appium_AutoTest\Caps\Caps.yaml", encoding="utf-8")
        datas = yaml.load(fs)
        for i in datas:
            if device == i["deviceDesc"]:
                if automationName != "appium":
                    i["desired_caps"]["automationName"] = automationName
                if noReset == False:
                    i["desired_caps"]["noReset"] = False
                desired_caps = i["desired_caps"]
                driver = webdriver.Remote("http://{0}:{1}/wd/hub".format(i["server_url"], i["server_port"]), desired_caps)
                return driver

3. conftest的改寫

conftest是比較關鍵的一部,因為它會調用BaseDriver()類中的base_driver()方法,以往我們的conftest是這樣定義的:

#登錄:無彈出框,不重置(保留狀態)
@pytest.fixture
def default_login_driver():
    driver = BaseDriver().basedriver()
    is_welcome(driver)
    yield driver
    driver.close_app()
    driver.quit()

但是現在不同了,這個basedriver()函數中必須傳入一個device的實參,這個實參是從哪里獲得的?pytest的fixture為我們提供了一種參數化的操作,fixture可以帶入參數params,依賴於這個fixture的一套測試會根據參數的不同運行多次,而被裝飾函數中通過特殊的request對象來訪問每個參數:request.param訪問的是列表中的每個元素

params=["Honor_5C", "YeShen"]

#登錄:無toast彈框,不重置
@pytest.fixture(params=params)
def login_common_driver(request):
    driver = BaseDriver().base_driver(device=request.param)
    is_welcome(driver)
    yield driver
    driver.close_app()
    driver.quit()

4. allure的使用

allure可以設置不同的特性:allure.feature(功能點)、allure.story(子功能點)、with allure.step(步驟):、allure.attach(附件)等,結合pytest,一個收集測試用例,一個生成測試報告。現在通過allure在測試用例中給測試報告增加一些特性

class TestLogin:

    #登錄成功——手機號、密碼正確
    @allure.feature("登錄模塊")
    @allure.story("登錄成功")
    @pytest.mark.usefixtures("login_common_driver")
    def test_login_success(self, login_common_driver):
        with allure.step("正常登錄"):
            IndexPage(login_common_driver).click_login()
            LoginPage(login_common_driver).input_phoneNumber(login_success_data["phoneNumber"])
            LoginPage(login_common_driver).input_passwd(login_success_data["passwd"])
            IndexPage(login_common_driver).click_later()
        with allure.step("獲取昵稱"):
            IndexPage(login_common_driver).click_me()
            nickName = UserInfoPage(login_common_driver).get_nickName()
        with allure.step("比對昵稱"):
            assert login_success_data["check"] == nickName

啟動多個appium-server

之前有想過python代碼執行appium命令的形式去自動啟動appium服務,但通過npm或cnpm安裝appium命令行都有報錯,只能手動啟動。很簡單,打開兩個appium客戶端,一個設置端口為4723,一個4726,啟動即可

配置jenkins任務

這方面的內容不做過多介紹,只看下構建和構建后的操作,其中allure-results是pytest運行測試用例生成的xml報告所在的目錄,jenkins上的Allure Commandline插件會自動解析xml,生成對應的html報告


allure測試報告

十分美觀吧,右上角的TREND顯示的是多次運行結果的趨勢,第7次到第19次都是5個fail,第20次6個fail

除此之外,allure報告的Behaviors功能中可以看到每個測試用例對應的測試步驟、功能、子功能等,測試報告還會標記出同一個測試用例是哪台手機執行的,如下圖,TestLogin.test_login_errorPasswd[Honor_5C]代表的執行機是榮耀暢玩5C

jenkins面板也展示了多次運行結果的趨勢

結語

pytest中fixture的參數化雖然能夠實現多台手機同時連接,但是運行並不是同時的,因為request.param讀取參數列表是遍歷讀取的,所以造成了一個測試用例,手機A先執行,手機B后執行(假設params=["手機A", "手機B"]),要想真正做到多台手機同時運行,就要用到多線程


免責聲明!

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



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