appium python client_Appium Python Client 简单解析

目录

我们clone下来之后,能够在Appium目录下看到如下的结构

.

├── __init__.py

├── common

│ ├── __init__.py

│ └── exceptions.py

├── saucetestcase.py

└── webdriver

├── __init__.py

├── common

│ ├── __init__.py

│ ├── mobileby.py

│ ├── multi_action.py

│ └── touch_action.py

├── connectiontype.py

├── errorhandler.py

├── mobilecommand.py

├── switch_to.py

├── webdriver.py

└── webelement.py

就如python本身语言一样还是比较清晰的,其中一层common目录以及saucetestcase我就不多说了,这个自己理解下就很简单了,其实大部分的篇幅还是注释,对作者表示致敬。

文件查看

那么自然我们就来详细看下webdrvier下面的文件了。一个一个来看吧。init.py

嗯,python工程、模块运行安装基础文件,该文件为空,但必须存在

mobileby.py

部分代码

from selenium.webdriver.common.by import By

class MobileBy(By):

IOS_UIAUTOMATION = '-ios uiautomation'

ANDROID_UIAUTOMATOR = '-android uiautomator'

ACCESSIBILITY_ID = 'accessibility id'

这个文件在这里就是对寻找控件的方式做了一个定义,当然其实看到这里,我不知道有没有同学就有疑问了,你能看懂这个是一个类,但这个类的参数By到底是个啥。好吧,其实我也不懂,但是我求助了webdriver的docs,By的定义如下

These are the attributes which can be used to locate elements. See the Locating Elements chapter for example usages.

The By implementation.

我初步理解了下,就是定位元素的一种方式,但是到底有哪些方式呢,其实还是没有看懂,所以进一步的看了下扩展。

class selenium.webdriver.common.by.By

Bases: object

Set of supported locator strategies.

classmethod is_valid(by)

CLASS_NAME = 'class name'

CSS_SELECTOR = 'css selector'

ID = 'id'

LINK_TEXT = 'link text'

NAME = 'name'

PARTIAL_LINK_TEXT = 'partial link text'

TAG_NAME = 'tag name'

XPATH = 'xpath'

定义的方式还是很多的,当然这个大家会在后面感觉到更熟悉的,我们接着往下看。

部分代码

import copy

from appium.webdriver.mobilecommand import MobileCommand as Command

class MultiAction(object):

def __init__(self, driver, element=None):

self._driver = driver

self._element = element

self._touch_actions = []

def add(self, *touch_actions):

"""Add TouchAction objects to the MultiAction, to be performed later.

:Args:

- touch_actions - one or more TouchAction objects describing a chain of actions to be performed by one finger

:Usage:

a1 = TouchAction(driver)

a1.press(el1).move_to(el2).release()

a2 = TouchAction(driver)

a2.press(el2).move_to(el1).release()

MultiAction(driver).add(a1, a2)

"""

for touch_action in touch_actions:

if self._touch_actions is None:

self._touch_actions = []

# deep copy, so that once they are in here, the user can't muck about

self._touch_actions.append(copy.deepcopy(touch_action))

def perform(self):

"""Perform the actions stored in the object.

:Usage:

a1 = TouchAction(driver)

a1.press(el1).move_to(el2).release()

a2 = TouchAction(driver)

a2.press(el2).move_to(el1).release()

MultiAction(driver).add(a1, a2).perform()

"""

self._driver.execute(Command.MULTI_ACTION, self.json_wire_gestures)

# clean up and be ready for the next batch

self._touch_actions = []

return self

其实这边其实第一个我表示我就没有理解,这个copy的模块有啥用,查看了下代码,其中使用到了深度复制deepcopy,从官方文档的解释来看像是连带着对象的属性也都会全部复制过来,并且开一个新的内存进行存放,应该是更有效率。从文件名字我们可以知道这是一个定义多操作的文件,然后从类的初始化我们能够看到很熟悉的参数,appium一个操作通常的参数,driver、element、action,首先定义了一个添加的方法,为了让单一的步骤肯定进行叠加,然后出现了perform这个重要的方法,这个方法是让用户去定义一个操作链,这个也就是这个所谓的多操作。那么其实看到这里我表示我又不是很这个_drvier.execute到底是个什么方法呢,继续查看了webdriver官方文档。如下解释

execute(driver_command, params=None)

Sends a command to be executed by a command.CommandExecutor.

Args:

driver_command: The name of the command to execute as a string.

params: A dictionary of named parameters to send with the command.

Returns:

The command’s JSON response loaded into a dictionary object.

那么就解释通了,两个参数,一个命令一个参数列表。同时也知道了原来返回的是一个字典,怪不得我看别的代码的时候不是很明白这个语法,接着看之后的文件分析就知道了,后面很多的操作封装都会用到这个方法的返回。

既然这个文件中引入了

from appium.webdriver.mobilecommand import MobileCommand as Command

那么我们就随着这个来讲下MobileCommand。

部分源码

class MobileCommand(object):

CONTEXTS = 'getContexts',

GET_CURRENT_CONTEXT = 'getCurrentContext',

SWITCH_TO_CONTEXT = 'switchToContext'

TOUCH_ACTION = 'touchAction'

MULTI_ACTION = 'multiAction'

OPEN_NOTIFICATIONS = 'openNotifications'

GET_NETWORK_CONNECTION = 'getNetworkConnection'

SET_NETWORK_CONNECTION = 'setNetworkConnection'

GET_AVAILABLE_IME_ENGINES = 'getAvailableIMEEngines'

IS_IME_ACTIVE = 'isIMEActive'

ACTIVATE_IME_ENGINE = 'activateIMEEngine'

DEACTIVATE_IME_ENGINE = 'deactivateIMEEngine'

GET_ACTIVE_IME_ENGINE = 'getActiveEngine'

TOGGLE_LOCATION_SERVICES = 'toggleLocationServices'

这个文件我不想讲了。。太过简单,没有东西可讲了。。。。。

switch_to.py

部分代码:

from selenium.webdriver.remote.switch_to import SwitchTo

from .mobilecommand import MobileCommand

class MobileSwitchTo(SwitchTo):

def context(self, context_name):

"""

Sets the context for the current session.

:Args:

- context_name: The name of the context to switch to.

:Usage:

driver.switch_to.context('WEBVIEW_1')

"""

self._driver.execute(MobileCommand.SWITCH_TO_CONTEXT, {'name': context_name})

其实我先是去查了switch_to,但是我不是很明白为啥文档里啥都没有写。然后我看了下Appium的文档,虽然明白这个是native和webview的一种切换,并且现在已经放入了Selenium3的规范中,但是还是不是很明白这个类的作用,直到我看到了下面的Sample

def test_move_back_to_native_context(self):

self._enter_webview()

self.driver.switch_to.context(None)

self.assertEqual('NATIVE_APP', self.driver.current_context)

def _enter_webview(self):

btn = self.driver.find_element_by_name('buttonStartWebviewCD')

btn.click()

self.driver.switch_to.context('WEBVIEW')

但是这个是不是可以自定义我还没有研究过,从例子看应该是可以的。

webdriver.py

其实到这个文件了已经是个集合了,我们回过头来看self.execute这个方法,其实现在就能够明白了,只要返回值的后面会有['value'],因为一个字典嘛。不查文档果然是看不懂的,当然也有很多方法直接返回一个字典的。具体我就不贴了,大家自己看了。

后续

其实结构还是蛮清晰的,但是就是流程,代码层面一步一步怎么走还不是很清晰,需要进一步看Sample再来理解了。不过总体我感觉比其他语言好理解点。因为其实就是一个Client嘛。哈哈

你可能感兴趣的:(appium,python,client)