Appium使用笔记整理及IOS的WDA工具的使用简介

概述

1、本人进入IT行业第一份工作是测试自动化方向的,所以针对这一段工作,对自动化测试工具Appium的学习、使用作出整理和总结。

2、对于appium工具的基础使用,注意以下几个关键字:
(1)appium只是针对android、ios等的自动化工具进行了集成;还有就是appium这个集成工具是使用nodejs开发的。
(2)Appium clients list。
(3)Appium Server Parameters。
(4)Capabilities Doc。
(4)appium/appium-idb。
(5)对于更深入的原理学习可以在github网站上查找,例如:
Conceptual Introduction。

针对python3语言对appium工具基础使用的笔记

如果系统上成功安装了Appium工具,则按如下方式使用Appium Python Client:
(1)从PyPi安装’Appium-Python-Client’模块:

pip install Appium-Python-Client

(2)可以开始编写脚本使用Appium-Python-Client:

(a)Android environment(真机):

from appium import webdriver

desired_caps = {}
desired_caps['platformName'] = 'Android'
# desired_caps['platformVersion'] = '8.1'
# desired_caps['automationName'] = 'uiautomator2'
desired_caps['deviceName'] = 'Android'
# desired_caps['app'] = PATH('../../../apps/selendroid-test-app.apk')
desired_caps['appActivity'] = '...' # 可以使用adb工具获取
desired_caps['appPackage'] = '...'  # 可以使用adb工具获取    
desired_caps['udid'] = '...'  	    # 可以使用 $ adb devices 获取
desired_caps['ignoreUnimportantViews'] = 'true'
# ...
# 如果需要其他的参数可以查看`Capabilities Doc`,并添加
# ...
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
# ...

(b)iOS environment(真机):

from appium import webdriver

desired_caps = {}
desired_caps['platformName'] = 'iOS'
# desired_caps['platformVersion'] = '11.4'
desired_caps['automationName'] = 'XCUITest'
desired_caps['deviceName'] = 'iPhone'
# desired_caps['app'] = PATH('../../apps/UICatalog.app.zip')
desired_caps['udid'] = '...'     # 可以使用 $ idevice_id -l 获取
desired_caps['bundleId'] = '...' # 可以使用 $ ideviceinstaller -l 获取
# ...
# 如果需要其他的参数可以查看`Capabilities Doc`,并添加
# ...
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
# ...

针对IOS自动化的相关笔记

1、在Mac OS系统下完成安装Appium。

2、针对WDA(WebDriverAgent)的使用笔记:

以下python3代码在Mac OS 10.13.6、Xcode10.0、Appium1.8.0、IOS12.0.1、Python 3.6.3工具环境下,并在第一步中成功安装Appium的条件下,测试成功。
代码的目的是为了实现IOS移动设备的切网功能,下面代码实现了核心代码,没有实现切网的全部代码。

(1)前面提到了Appium工具是一个集成工具,针对IOS的自动化实现,是使用了WDA工具;

(2)使用WDA可以实现对手机的直接控制,具体介绍和简单使用如下:

a. 先使用xcodebuild命令启动WDA软件;

project = "/Applications/Appium.app/Contents/Resources/app/node_modules\
	/appium/node_modules/appium-xcuitest-driver\
	/WebDriverAgent/WebDriverAgent.xcodeproj"
	
scheme = 'WebDriverAgentRunner'

commond =  "xcodebuild -project %s -scheme %s -destination 'id=%s' test" % (project, scheme, udid)

b. 再使用iproxy命令,使得Mac电脑指定端口与IOS设备上WDA软件的端口进行映射;

commond = "iproxy %s 8100 %s" % (mac_port, udid)

c. 在a、b步骤中的命令工具都成功启动后,即可使用HTTP请求的方式访问Mac本地(即localhost)的指定的不同端口(即mac_port)来控制对应的IOS设备。
例如,使用GET方式,访问“http://localhost:/status”,可以获取SessionID。示例代码如下:

def get_session(mac_port):
	"""访问Mac上的指定端口,获取指定手机与Mac的SessionId"""
    rs = http_get2('http://localhost:%s/status' % mac_port)
    if not rs.startswith('error'):
        rs_json = json.loads(rs, encoding='utf-8')
        session_id = rs_json['sessionId']
    return session_id

上面的三个步骤简单阐述了直接使用WDA控制IOS移动设备的方法。更多信息可参考Github网站相关资源

完整测试代码如下:

#!/usr/bin/env python3

import threading
import subprocess
import json
import urllib.request
import time
from xml.dom import minidom
from http import client

def ex_cmd3(cmd):
    """子进程工具:

    xcodebuild & iproxy命令的子进程没有进行时间控制,而是采用任务完成后直接杀进程。
    该处可以自行优化。"""
    p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
    p.wait()


def http_get2(url):
    """发送GET请求"""
    try:
        gt = urllib.request.urlopen(url,timeout=60)
    except Exception as ex:
        res = 'error:%s' % ex
    else:
    	if gt.getcode() == 200:
    	    resp = gt.read()
    	    resp_str = resp.decode('utf8')
    	    res = resp_str
    	else:
    	    res = 'error:%d' % gt.getcode()
    	    gt.close()
    return res


def req_post(req_data, session_id, action, mac_port):
    """发送POST请求,进行操作ios界面内容。"""
    req_data_json = json.dumps(req_data)
    url = 'http://localhost:%s/session/' % (mac_port) + session_id + action
    header = {"Content-type": "application/json"}
    conn = client.HTTPConnection("localhost", int(mac_port))
    conn.request('POST', url, req_data_json, header)
    res = conn.getresponse()
    res = res.read()
    conn.close()
    return res


def start_up_wda(mac_port,udid):
    """ 启动WebDriverAgent工具,并获取指定IOS移动设备的session id。 """


    def startup_wda(mac_port, udid):
    	"""启动xcodebuild & iproxy:
        WDA为IOS软件包,使用xcodebuild命令启动;
        使用iproxy命令使Mac与iPhone建立端口映射。"""

    	project = "/Applications/Appium.app/Contents/Resources/app/node_modules\
/appium/node_modules/appium-xcuitest-driver\
/WebDriverAgent/WebDriverAgent.xcodeproj"
    	# print(project)
    	scheme = 'WebDriverAgentRunner'
    	commond =  "xcodebuild -project %s -scheme %s -destination 'id=%s' test" % (project, scheme, udid)
    	threading.Thread(target=ex_cmd3, args=(commond,)).start() # xcodebuild命令的更多信息,使用 $ xcodebuild --help来查询
    	print("xcodebuild命令行已启动!")
    	time.sleep(30)
    	commond = "iproxy %s 8100 %s" % (mac_port, udid)  # 每个IOS上WDA软件的服务端口为8100											  # 而Mac由于连接多个手机,Mac上的端口可以自行设定。
    	threading.Thread(target=ex_cmd3, args=(commond,)).start()
    	print("iproxy命令行已启动!")


    def get_session(mac_port):
    	""" 访问Mac上的指定端口,获取指定IOS移动设备与Mac电脑的 session id。 """
    	rs = http_get2('http://localhost:%s/status' % mac_port)
    	if not rs.startswith('error'):
            rs_json = json.loads(rs, encoding='utf-8')
            session_id = rs_json['sessionId']
    	return session_id


    startup_wda(mac_port, udid)
    time.sleep(20)
    session_id = get_session(mac_port)
    return session_id


def get_source(mac_port, session_id):
    """ 获取source """
    rs = http_get2('http://localhost:%s/session/%s/source' % (mac_port, session_id))
    source = ''
    if not rs.startswith('error'):
        rs_json = json.loads(rs, encoding='utf-8')
        source = rs_json['value']
    return source


def write_source_xml(str_source, session_id):
    """ 将获取到的source写入xml文件 """
    source_xml = open(session_id + '_source.xml', 'w')
    source_xml.write(str_source)
    source_xml.close()
    print(session_id + '_source.xml文件创建成功!')


def get_target(element_type, session_id, element_name):
    """ 从pagesource中获取目标控件的中间点。 """
    with open(session_id + '_source.xml', 'r', encoding='utf8') as fh:
        dom = minidom.parse(fh)
        root = dom.documentElement
        # XCUIElementTypeIcon XCUIElementTypeCell
        iconList = root.getElementsByTagName(element_type)
        for icon in iconList:
            name = icon.getAttribute('name')
            if element_name == name:
                x = int(icon.getAttribute('x'))
                y = int(icon.getAttribute('y'))
                width = int(icon.getAttribute('width'))
                height = int(icon.getAttribute('height'))
                break
        return {"x": x+width/2,"y": y+height/2}


def tap_by_name(session_id, mac_port, name):
    """ 使用POST请求,访问http://localhost:/session/wda/tap/0,进行点击目标控件。 """

    source = get_source(mac_port, session_id)
    if source != '':
        write_source_xml(source, session_id)
        if 'set' == name:
            req_data = get_target('XCUIElementTypeIcon', session_id, "设置")
            req_post(req_data, session_id, '/wda/tap/0', mac_port)
            source = "SUCCESS"
        elif 'Wi-Fi' == name:
            req_data = get_target('XCUIElementTypeCell', session_id, "Wi-Fi")
            req_post(req_data, session_id, '/wda/tap/0', mac_port)
            source = "SUCCESS"
        else:
            req_data = get_target('XCUIElementTypeCell', session_id, "无线局域网")
            req_post(req_data, session_id, '/wda/tap/0', mac_port)
            source = "SUCCESS"
    return source


if __name__ == "__main__":
    mac_port = "8723"
    session_id = start_up_wda(mac_port, 'c259a97742e575999c9706a8b97cff7bf5046e9f')
    source = tap_by_name(session_id, mac_port, 'set')
    if source.startswith("SUCCESS"):
    	print("'set'点击成功!")
    source = tap_by_name(session_id, mac_port, 'Wi-Fi')
    if source.startswith("SUCCESS"):
    	print("'Wi-Fi'点击成功!")

# 杀掉进程可以使用 $ kill -9 `lsof -t -i:port` 命令;该部分代码可以自行实现,或使用更好的关闭子进程方式。

你可能感兴趣的:(IOS移动自动化,appium使用笔记,移动自动化)