文档章节

转-Appium实战-基类的构建

o
 osc_z1hvg4cu
发布于 2018/04/24 16:47
字数 1357
阅读 21
收藏 0

精选30+云产品,助力企业轻松上云!>>>

套用UnitTest构建测试

UnitTest是Python的测试框架,我们这次的实战就是基于这个测试框架来构建的,所以就把基类用UnitTest构建起来。

扫盲,什么是UnitTest?怎么用UnitTest?

  1. 《Hello PyUnitTest》
  2. 《为你的测试结果打印案例名称》
  3. 《测试多个类》
  4. 《测试用例的初始化和结束函数》
  5. 《引入其他类》
  6. 《第一个web自动化》
  7. 《加上测试报告》
  8. 《测试多个文件》

以上是我自己在学习UnitTest过程中做的一些记录。

测试案例的颗粒度必须要细,而且测试一个点之后最好进行环境的还原,因此我的基类是这么写的。

新建一个文件叫BestTestCase,然后输入下面的代码:


import unittest
from appium import webdriver
import config

class AppTestCase(unittest.TestCase): def setUp(self): desired_caps = { 'platformName': config.CONNECT['platformName'], 'platformVersion': config.CONNECT['platformVersion'], 'deviceName': config.CONNECT['deviceName'], 'appPackage': config.CONNECT['appPackage'], 'appActivity': config.CONNECT['appActivity'] } self.driver = webdriver.Remote(config.CONNECT['baseUrl'], desired_caps) def tearDown(self): self.driver.quit()

这样写,只要其他的测试类来集成这个类就行了,就不用再每个测试类中写setUp和tearDown了,而且每次测试完功能点后就会自动退出APP,还原环境。

导入包有一个import config,这个是我做的一个配置文件,命名为config.py,我把一些不常修改的参数往这里丢。比如这个初始化的参数,我就这样放了。


config.py

CONNECT = {
    'platformName': 'Android',
    'platformVersion': '4.4.4',
    'deviceName': '5136b01e', 'appPackage': 'com.weizq', 'appActivity': 'com.zztzt.android.simple.app.MainActivity', "baseUrl": "http://127.0.0.1:4723/wd/hub" }

构建通用方法

UnitTest的基类构建完之后,我们要对基础的方法做一些封装。

常用的功能大概有这些:寻找元素的各种方法,系统的按键,滑动,获取坐标,截图等。废话不多说,先上代码:


from selenium.webdriver.support.expected_conditions import NoSuchElementException
from selenium.webdriver.support.ui import WebDriverWait
import time as t import config class WebDdriver(object): def __init__(self, driver): self.driver = driver def __str__(self): return 'webDdriver' def find_element(self, *loc): """ 定位元素,定位正确后返回元素的信息,外部调用传入元组参数必须有*, 例如: find_element(*self.native_caixun) :param loc: 元组类型,结构必须是(By.NAME, u'财讯') :return: element """ try: element = WebDriverWait(self.driver, 10).until(lambda x: x.find_element(*loc)) return element except NoSuchElementException, e: print 'Error details :%s' % (e.args[0]) def find_elements(self, *loc): """ 定位元素,定位正确后返回元素的信息,外部调用传入元组参数必须有*, 例如: find_elements(*self.native_caixun) :param loc: 元组类型,结构必须是(By.NAME, u'财讯') :return: elements """ try: # return self.driver.find_elements(*loc) elements = WebDriverWait(self.driver, 10).until(lambda x: x.find_elements(*loc)) return elements except NoSuchElementException, e: print 'Error details :%s' % (e.args[0]) def get_title(self): """ 获取页面的标题 :return: str, 页面的标题 """ title = self.find_elements(*config.COMMON['view_title'])[0].text return title @property def wait(self): t.sleep(5) def getScreenshot(self, name, url, form='png'): t.sleep(2) self.driver.get_screenshot_as_file(url + name + "." + form) def sysback(self): """ 系统的返回按钮 :return: None """ self.driver.keyevent(4) def get_size(self): """ 获取当前屏幕的分辨率 :return: int, x*y """ size = self.driver.get_window_size() return size def swipe_to_up(self): """ 从下往上滑动 :return: None """ window_size = self.get_size() width = window_size.get("width") height = window_size.get("height") self.driver.swipe(width / 2, height * 3 / 4, width / 2, height / 4, 500) def swipe_to_down(self): """ 从上往下滑动 :return: None """ window_size = self.get_size() width = window_size.get("width") height = window_size.get("height") self.driver.swipe(width / 2, height / 4, width / 2, height * 3 / 4, 500) def swipe_to_left(self): """ 从右往左滑动 :return: None """ window_size = self.get_size() width = window_size.get("width") height = window_size.get("height") self.driver.swipe(width / 4, height / 2, width * 3 / 4, height / 2, 500) def swipe_to_right(self): """ 从左往右滑动 :return: None """ window_size = self.get_size() width = window_size.get("width") height = window_size.get("height") self.driver.swipe(width * 4 / 5, height / 2, width / 5, height / 2, 500) def getLocation(self, *loc): """ 获取元素的定位信息,外部调用传入元组参数必须有*, 例如: (*self.native_caixun) :param loc: 元素的定位方式 :return: list, [x, y] """ locaX = self.find_element(*loc).location.get('x') locaY = self.find_element(*loc).location.get('y') rst = [locaX, locaY] return rst

注释我应该写的很清楚了,就把一些比较重要的地方做一些解释,在init中先把刚刚构建的driver初始化了,让类中的其他方法可以使用driver。

两个最重要的方法,find_element和find_elements做一下重点说明。正常来说,找元素的方法有这么几种,name、id、xpath、tag、class_name、link_text等,但是如果做这么多封装,代码就会显得非常多,当然,如果没有其他办法的话,那就只能老老实实的枚举了,但是如果去看webdriver的源码,就能找到这么一个方法。源码是这样的:


class By(object):
    """ Set of supported locator strategies. """ ID = "id" XPATH = "xpath" LINK_TEXT = "link text" PARTIAL_LINK_TEXT = "partial link text" NAME = "name" TAG_NAME = "tag name" CLASS_NAME = "class name" CSS_SELECTOR = "css selector" @classmethod def is_valid(cls, by): for attr in dir(cls): if by == getattr(cls, attr): return True return False

那么也就是说,在webdriver的方法源码中已经帮我们枚举了,那么我们就可以直接调用这个方法,,做参数传入就行了。方法有做入参检查,因此传入参数要求是tuple的类型,所以元素我就全部剥离出来用配置文件处理,配置文件的内容我们就这样写:


from selenium.webdriver.common.by import By
CAIXUN = {
    'tuijian': (By.NAME, u'推荐'),
    'gupiao': (By.NAME, u'股票'), 'jijin': (By.NAME, u'基金'), 'zhaiquan': (By.NAME, u'债券'), 'xinsanban': (By.NAME, u'新三板'), 'zixunneirong': (By.ID, 'com.weizq:id/new_title'), # 财讯记录列表,用find_elements调用 'imgurl': '/Users/SvenWeng/PycharmProjects/WeStock/img/caixun/', 'title': [ ['tuijian', 'tuijianneirong'], ['gupiao', 'gupiaoneirong'], ['jijin', 'jijinneirong'], ['zhaiquan', 'zhaiquanneirong'], ['xinsanban', 'xinsanbanneirong'] ], 'jiahao': (By.CLASS_NAME, 'android.widget.ImageView'), 'pindao': (By.ID, 'com.weizq:id/text_item'), }

中间的那些元素就直接这样配置,如果开发进行了一些修改,那么我们就直接改这里就行了。这就是Page Object最大的好处了。

最后

最底层的构建就先这样处理了。当然还有其他方法需要构建,比如某个页面的元素定位方法。已经方法的调用。

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

以太坊智能合约开发常见的10个安全问题

本文介绍CheckMarx安全研究小组通过扫描公开的以太坊智能合约所发现的Solidity智能合约开发中常见的十大安全问题,其中__未检查的外部调用__ 和 高成本循环 分列排行榜前两名。该安全问题排行...

区块链教程
35分钟前
15
0
Android Studio写flutter快捷键

1.stl :代表StatelessWidget 2.stf :StatefulWidget 3.cmd + shift + 减号 :折叠所有代码 4.cmd + 减号 :折叠当前代码块 5.ctrl + r :编译运行 6.cmd + s :hot reload 7.cmd + { :回到...

一代码农码一代
48分钟前
17
0
远程桌面如何修改登录密码

打开运行, C:\Windows\explorer.exe shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0} 即可 https://www.itexperience.net/10-ways-to-change-password-in-remote-desktop-session/......

ethanleellj
50分钟前
11
0
easyui的menu接收后台集合,并且根据集合利用appendItem动态生成菜单项,判断菜单项的字数大于指定长度,则多余字符以。。。显示,并且悬浮提示

JSP: <a id="bb" href="javascript:void(0);" class="easyui-menubutton" data-options="menu:'#layout_north_stMenu222',iconCls:'icon-cologne-sign-out'" >导出</a><div id="aaa" style......

文文1
51分钟前
13
0
Mysql主从同步

1主从同步 1.1Master 1.1.1配置--编辑 my.cnf #编辑 mysql 的 /etc/my.cnf 配置文件vi /etc/my.cnf#添加如下配置server-id=1 #设置服务 IDlog_bin=mysql-bin #启动 binlog...

风雪满弓刀
今天
14
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部