Appium 各位交流一下 业务设计思路

姜衍 · June 20, 2022 · Last by 迷龙 replied at June 29, 2022 · 6200 hits

想设计出 ios+web+android 一体的框架

我目前设计框架是 POM(project object model) 设计模式

然后阐述一下自己的设计思路

在 Page 木内一个 py 文件封装一个功能或者一个页面的操作元素 一些单独的操作元素,封装成方法,然后每个页面 page 内都会有个核心流程方法
然后说一下我为什么要封装成方法而不是变成类变量,因为我感觉封装好后,直接调用比较方便,然后也能保证元素唯一性 (有些元素可能是好几个页面的按钮)
维护元素时能很清楚。

我的框架目录

common:
封装元素,循环检测元素是否存在,定位不到抛出指定异常,并记录在 Allure 测试报告内

page 的封装

封装保证元素路径的唯一性, 进行设计测试用例时,可以灵活调用每个页面的每个元素。

testcases:
一个 py 对应一个业务流程

更新:重新修改元素操作方法

点击输入等操作内 融合 find_elements 和 find_elements 用元组传入

def find_elements(self, locate, img_doc, timeout=10, frequency=0.5):
    """
    检测定位元素是否存在 多个元素
    :param locate: 元素定位方式+路径
    :param img_doc: 截图说明
    :param timeout: 等待的超时时间
    :param frequency: 轮询频率
    :return:  WebElement元素地址 返回list类型
    """
    try:
        el = None
        wait = WebDriverWait(self.driver, timeout, frequency)
        if locate[0] == 'id':
            el = wait.until(lambda diver: self.driver.find_elements(By.ID, locate[1]), message='没找到该元素')
        elif locate[0] == 'xpath':
            el = wait.until(lambda diver: self.driver.find_elements(By.XPATH, locate[1]), message='没找到该元素')
        elif locate[0] == 'name':
            el = wait.until(lambda diver: self.driver.find_elements(By.NAME, locate[1]), message='没找到该元素')
        elif locate[0] == 'css_selector':
            el = wait.until(lambda diver: self.driver.find_elements(By.CSS_SELECTOR, locate[1]),
                            message='没找到该元素')
        elif locate[0] == 'tag_name':
            el = wait.until(lambda diver: self.driver.find_elements(By.TAG_NAME, locate[1]), message='没找到该元素')
        elif locate[0] == 'partial_link_text':
            el = wait.until(lambda diver: self.driver.find_elements(By.PARTIAL_LINK_TEXT, locate[1]),
                            message='没找到该元素')
        elif locate[0] == 'link_text':
            el = wait.until(lambda diver: self.driver.find_elements(By.LINK_TEXT, locate[1]), message='没找到该元素')
        elif locate[0] == 'class_name':
            el = wait.until(lambda diver: self.driver.find_elements(By.CLASS_NAME, locate[1]), message='没找到该元素')
        elif locate[0] == 'predicate':
            el = wait.until(lambda diver: self.driver.find_elements_by_ios_predicate(locate[1]), message='没找到该元素')
        elif locate[0] == 'accessibility_id':
            el = wait.until(lambda diver: self.driver.find_elements_by_accessibility_id(locate[1]), message='没找到该元素')
        if el is not None:
            return el
        self.logger.info("<{}>,元素<{}>定位成功".format(img_doc, locate[1]))
    except Exception as e:
        self.logger.error("<{}>元素<{}>定位失败!".format(img_doc, locate[1], ))
        raise e

def click(self, locate, img_doc):
    """
    点击按钮
    :param locate:  元素定位方式+路径  元组类型传入
    :param img_doc: 截图说明
    """
    try:
        if len(locate) == 2:
            el = self.find_element(locate, img_doc)
            el.click()
            self.logger.info("点击<{}>成功,元素和定位方式:{}".format(img_doc, locate))
        else:
            el = self.find_elements(locate, img_doc)
            el[locate[2]].click()
            self.logger.info("点击<{}>成功,元素和定位方式:{}".format(img_doc, locate))
    except Exception as e:
        self.logger.error("点击<{}>失败,元素和定位方式:{}".format(img_doc, locate))
        self.add_allure_attach(img_doc)
        raise e
共收到 9 条回复 时间 点赞
Mango · #1 · June 20, 2022
Author only
姜衍 #2 · June 20, 2022 Author
Mango 回复

之前想过将元素定位变量,但是根据实际运用,感觉分成固定操作比较好,点击是点击,输入框是输入框,他不可能让点击进行输入或者什么的操作,所以直接维护成了一个方法,如果想用该方法就调用就好了

有个问题,这么多端合并到一起,能同时运行吗?

就是发版了,我要跑一下(安卓/iOS/web)端的冒烟 case,能在一起同时运行吗?(python main.py)

你在用 pytest 框架 写 自己的 业务测试用例,并且 对 selenium 的 API 做了简单的封装,并使用了 PO 设计模式。

框架设计 被用烂了,作为公开框架,应该具备:

  1. 框架提供独立的安装,pip 安装 或 exe 安装程序,或别的独立的安装程序。至少应该和业务代码剥离吧!

  2. 框架的版本号,有版本号才能更好的迭代和维护。

  3. 框架的 API 和 文档,如果是给别人用的话。

-- 无意冒犯,只是更正一下业务代码的设计框架设计 的区别。

如果方向不对,后面的道路将会满是泥泞。

看了下,这是个应用了 page object 后比较常规的写法,没啥大问题,用例数量少的情况下基本够用了。后续用例数量多了或者执行多了后,可按需补充更多的能力。比如:

错误排查相关:
1、失败允许自动重跑
2、失败时自动截图及 dump 控件树,便于排查失败原因。有全程录屏最好。

长期运行维护相关:
1、全局配置管理。比如用户名、密码、执行设备、appium capibility 参数这些。这些参数最好既支持读取配置文件,也支持命令行乃至环境变量传入,比较灵活。
2、appium 实例管理。比如后续放到 jenkins 上,可能会一个节点同时多个自动化在跑。而 appium 目前暂时不支持并行多 session ,所以需要自行管理多个 appium 实例,包括自动启动、自动分配空闲端口号、自动关闭进程、自动记录日志。
3、框架与项目分离。多个项目使用时会存在多个仓库,此时升级框架部分的公共能力会非常困难。必须要把框架的能力独立出来单独的包中,项目通过依赖的方式进行引入,这样才能具备更好的维护性。

姜衍 #7 · June 21, 2022 Author
陈恒捷 回复

appium 一些启动需要的参数,目前维护在了 yaml 文件内,然后多设备运行的话,已经有代码,但是目前这体谅运用不到, 就被搁置了,然后在做元素的处理,还是想保证元素的唯一性,所以目前将元素变成类变量形式,测试数据还是维护在 yaml 文件内。
这几天也看了很多 github 上的源码,发现 ios 和安卓很多人都是写两套页面元素定位方法,然后运行根据机型进行判断调用业务流程

1.为了防止元素定位失败,会在一些进行页面跳转的操作时增加强制等待, 定位封装了 wait.until 方法 会循环找元素
元素一般找不到基本是没有该元素,所以目前没有增加失败重跑机制
1.1.失败自动截图已经添加了,但是查了很多例子,发现只能截取在哪个页面定位失败,无法精确到指定元素位置
截图 dump 树这个,移动端没有看到有类似方法, 不过封装了在浏览器 (网页) 定位失败时会打开 dump 树进行失败截图
2.Jenkins 这个,因为目前业务流程还没编写完成,还没想到这方面,有空会补充这方面的知识,看看能否去运用
2.1 全程录制这个,考虑过,想使用 adb 命令进行实现,但是目前还停留在理论阶段

挺好的,有分层思想已经很好了,随着使用过程中发现一些缺陷,慢慢优化就好了。

这样维护起来太麻烦了,建议每个端先做好再考虑合并的事。可以在每个端进行代码编写的时候考虑一下以后会合并的情况,提前设计。

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up