1. 程式人生 > >Appium 並發多進程基於 Pytest框架

Appium 並發多進程基於 Pytest框架

height 測試框架 pack 等待 code pca osi ESS tom

前言:

之前通過重寫unittest的初始化方法加入設備參數進行並發,實現了基於unittest的appium多設備並發,但是考慮到unittest的框架實在過於簡陋,也不方便後期的Jenkins的持續集成,所以想換一個框架來使用。

那麽通過調研,pyhon+pytest+allure 這套框架很不錯,pytest是一個單元測試框架,他可以集成很多插件,包括出錯重試,參數化,等。在此特別是基於他的allure插件,能夠和Jenkins完美兼容,生成美觀強大的測試報告。

改造思路:

pytest框架和unittest框架明顯不同,通過命令行啟動,讀取響應目錄下的test開頭的文件,進行執行用例。

而unittest卻是通過將用例加載到TestSuite中,運行隨測試集來執行用例

所以這邊多進程就要換一種思路進行了。

基於pytest的結構和運行方式,那麽思路如下:

運行方式:

1. pytest目錄下會先加載conftest.py運行。

2. 該目錄下加載test開頭的py文件

3. 加載文件中Test開頭的類

4. 加載Test類下test開頭的方法

5. 通過命令行pytest.main([1, 2 ,3])帶入1 2 3參數進行運行

解決思路:

1. 通過命令行把不同設備的參數傳遞給conftest.py

2. conftest中,使用傳遞過來的設備參數,連接設備到appium,並生成driver對象

3. 在各自的測試類和測試方法中,調用driver對象,進行測試操作

4. 生成allure測試報告

實現:

1. 通過命令行傳遞參數:

run中的設備池:

def devices_Pool():
    devices_list = []
    for i in range(0, len(getDevices())):
        _initApp = {}
        _initCaps = {}
        _initApp["devices"] = getDevices()[i]
        _initCaps["deviceName"] = getDevices()[i]
        _initCaps[
"platformVersion"] = getPhoneInfo(devices=_initCaps["deviceName"])["release"] _initCaps["platformName"] = "Android" _initApp["port"] = str(random.randint(4700, 4900)) _initApp["bport"] = str(random.randint(4700, 4900)) _initApp["systemPort"] = str(random.randint(4700, 4900)) _initCaps["automationName"] = "UiAutomator2" _initCaps["appPackage"] = cn.vsx.vc _initCaps["appActivity"] = .activity.RegistActivity _initApp["Caps"] = _initCaps devices_list.append(_initApp) print(len(getDevices())) print(len(devices_list)) return devices_list

run中,多進程調用啟動命令行,並傳遞參數:

def runnerPool(device_list):
    getdevice = getDevices()
    with ProcessPoolExecutor(len(getdevice)) as pool:
        pool.map(runPytest, device_list)


def runPytest(device):
    print(f"cmdopt is {device}")
    report = f"report-{device[‘Caps‘][‘deviceName‘]}".split(":", 1)[0]
    try:
        os.system(f"del /s /q E:\\appium-pytest\\{report}")
        time.sleep(1)
        os.system(f"rd /s /q E:\\appium-pytest\\{report}")
        time.sleep(1)
        print(f"{report} report has deleted")
    except:
        print("no directory existed")
    finally:
        print(f"pool run device is {device[‘devices‘]}")
        pytest.main(["../TestCases/", f"--cmdopt={device}", "--alluredir", f"../{report}/xml"])
        time.sleep(1)
        os.system(f"allure generate ../{report}/xml -o ../{report}/html")

conftest文件中,獲取命令行傳遞過來的參數:

def pytest_addoption(parser):
    parser.addoption("--cmdopt", action="store", default="device", help="None")

@pytest.fixture(scope="session")
def cmdopt(request):
    return request.config.getoption("--cmdopt")

conftest中通過傳遞的參數,生成連接對象:

@pytest.fixture(scope="session")
def connectDevice(cmdopt):
    device = eval(cmdopt)
    device_caps = {}
    device_caps["platformVersion"] = getPhoneInfo(device["Caps"]["deviceName"])["release"]
    device_caps["platformName"] = "Android"
    device_caps["automationName"] = "UiAutomator2"
    device_caps["deviceName"] = device["Caps"][deviceName]
    device_caps["udid"] = device["Caps"][deviceName]
    device_caps["appPackage"] = "cn.vsx.vc"
    device_caps["appActivity"] = ".activity.RegistActivity"
    device_caps["noReset"] = True
    device_caps["noSign"] = True
    device_caps["unicodeKeyboard"] = True
    device_caps["resetKeyboard"] = True
    device_caps["systemPort"] = int(device["systemPort"])
    remote = "http://127.0.0.1:" + str(device["port"]) + "/wd/hub"
    print(f"wo shi pytest {device_caps}")
    driver = webdriver.Remote(remote, device_caps)
    return driver

測試用例中,使用對象來進行操作:

class Test_groupCall():
    @allure.feature("group_call")
    @allure.story("login")
    def test001_login(self, connectDevice):
        ‘‘‘登入選擇單位‘‘‘
        WebDriverWait(connectDevice, 10).until(
            lambda x: x.find_element_by_xpath(
                "//android.widget.TextView[contains(@text, ‘選擇單位‘)]").is_displayed())  # 驗證等待10秒超時
        x = connectDevice.get_window_size()[width]  # 獲取當前屏幕寬
        y = connectDevice.get_window_size()[height]  # 獲取當前屏幕高
        a, b = 170 / 768, 790 / 1184  # 選擇單位222系數
        connectDevice.find_element_by_xpath("//android.widget.TextView[contains(@text, ‘選擇單位‘)]").click()

最後:

多設備連接時,一定要註意給每個desired_caps中加入每個設備自己的systemPort,否則會連接不上多設備,至此改造成功,最後生成的報告也讓人滿意:

技術分享圖片

Appium 並發多進程基於 Pytest框架