UiAutomator 开源项目:小红书移动 UI 并发自动化测试实践之 DisCartierEJ

刘大头 · 2017年06月04日 · 最后由 刘大头 回复于 2019年09月19日 · 2813 次阅读
本帖已被设为精华帖!

开源项目:小红书移动 UI 并发自动化测试实践之 DisCartierEJ

@ Arthor: Juan Liu
@ Date : 2017.06.03

相关背景

随着小红书发展,各种自动化产品也在逐渐使用,提高工作效率、节省时间,也更多的保证了正确性。在小红书,移动 UI 自动化方面,尝试的项目之一就是当前的这个 DisCartierEJ 项目。

在这个项目进行两个月左右的时候,我写了一篇文章总结了当时的思路小红书自动化平台实践之 Cartier,主要是讲解了思路方面和架构方面,这次更多的是关注代码方面,在架构方面也有了一点点改进。

开源背景

  1. 项目基本上达到了预期的目标,可以无连接的实现多台设备同时并行正确运行。
  2. 开源出来,希望在大家使用的过程中,更加的优化项目和代码。
  3. 实习快结束了,开源也是一次回头过来好好看看设计思路和代码的过程,优化交付给下一位同事。

github 地址

DisCartierEJ 的地址:https://github.com/haifengrundadi/DisCartierEJ

CartierEJ 的地址:https://github.com/haifengrundadi/CariterEJ

DisCartierEJ 的优点

  1. 利用 docker 将 appium 及其依赖的工具放在一个容器中,这样使用者(比如开发或者其他相关测试人员等)只需要 pull 镜像文件,就可以运行了,不需要一个个去安装各种依赖,减去不必要的时间。ps:我刚接触的时候,花了一天多的时间装了各种软件,遇到各种配置问题,更会浪费许多时间,这些时间对仅仅使用的人来说,毫无必要,对需要开发的人来说,犯错还是有价值的。

  2. 利用 stf 管理设备,这样不管你在哪都可以进行使用手机,不必每次都将手机通过 usb 连接计算机。更为重要的是,你可以任意选择你想要的手机,选择多台同时运行,相当于一个资源池的概念。ps:你在出差,你身边没有手机,突然想运行一个 case,这个时候打开电脑,运行就好。

  3. 多台并行运行 case。之前,都是一个计算机上运行一个 appium,一个 appium server 对应一个 device,很难将一个 case 一下子运行在多个设备上,测试兼容性不是很方便。

  4. 在 jenkins 可以进行巡检,并将结果通过展示出来,(这个还没有实现,有尝试过,但是没有办法把本地运行 stf 的机器(需要将手机本地连接到一个主机上)当做腾讯云的一个 slave,而暂时暂停(ssh 连接,如果通过域名,应该是可以作为一个 slave 的))。

DisCartierEJ 的架构

上图是 DisCartierEJ 的架构图,下面根据一个使用者的流程对这个图进行介绍。

  1. 深蓝色部分,用户希望自己的 case 在三台设备上跑一下。
  2. 将自己 case pull 到 github 或者能下载的地方

    https://github.com/haifengrundadi/CartierEJ.git

  3. git clone DisCartierEJ 代码

    git clone https://github.com/haifengrundadi/DisCartierEJ.git

  4. 将 DisCartierEJ 中的 Dockerfile 中的获取 CartierEJ 的代码更改为步骤 2 的地址,并生成对应的镜像。

    ...
    #=======================================
    # pull code from git
    #=======================================
    RUN git clone https://github.com/haifengrundadi/CartierEJ.git
    ...

    生成对应的镜像

    docker build -t appium_cartierej_docker:latest .

  5. 运行 DisCartierEJ,它会去 STF 上寻找三台符合要求的设备返回。

  6. 然后将返回来的三个设备信息,根据设备名生产三个文件夹,并将每个设备的信息注入到相应文件夹下的 docker_compose.yml 中的环境变量中。

  7. 启动 up 每一个文件夹下的 docker_compose.yml,生成对应的容器,每个容器会先启动 appium 然后运行 case。

  8. 对应的日志会映射在本地,jenkins 根据日志,生成 report。

Demo 演示

下面我们运行一个实例来演示 DisCartierEJ 项目。

需求: 将一个 login 的 case 运行在 stf 所有可用的手机上。

前置条件: 先下载 Docker,并运行。

正式步骤:

  1. 编写一个 login case,所有的 case 要按照 CartierEJ 进行编写(非常简单)。

    只需要 clone 上面的代码即可。

    git clone https://github.com/haifengrundadi/CartierEJ.git

  2. 修改或者按着模板添加自己的功能,然后将代码上传到自己的 github 上。

    自己现在 github 上新建一个项目,名字叫 CartierEJ。
    其他如何 push 到 github 上,看 github 的提示。

  3. 从 github 上 git clone DisCartierEJ 这个项目。将 DisCartierEJ 中的 Dockerfile 中的获取 CartierEJ 的代码更改为步骤 2 的地址,并生成对应的镜像。

    ...
    #=======================================
    # pull code from git
    #=======================================
    RUN git clone https://github.com/haifengrundadi/CartierEJ.git
    ...

    生成对应的镜像(这个第一次比较慢,因为镜像比较大)

    docker build -t appium_cartierej_docker:latest .

  4. 修改 DisCartierEJ 的配置文件 config.py。见下

  5. 进入到 DisCartierEJ 的 core 的 generator.py

    python generator.py

config.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# the apk place in container
APK_NAME = "/apk_shell/xxx.apk"

# stf_url address
STF_URL = "http://xxx.xxx.xxx.xxx:7100/api/v1/devices"
"""
access token of stf
STF uses OAuth 2.0 for authentication. In order to use the API,
you will first need to generate an access token. Access tokens
can be easily generated from the STF UI. Just go to the Settings
tab and generate a new access token in Keys section.
Don't forget to save this token somewhere, you will not be able to see it again.
"""
TOKEN = "xxx"

STF_DELETE_URL = "http://xxx.xxx.xxx.xxx:7100/api/v1/user/devices/"

# some variables in desired_capablities
PLATFORM_NAME = 'Android'
NEW_COMMAND_TIMEOUT = 60

# come infomation needed by docker_compose.yml
APPIUM_CARTIEREJ_IMAGE = "appium_cartierej_docker:latest"
PORTS = 4723
APPIUM_CARTIEREJ_CMD = "bash /app_shell/app.sh"
APP_APK_VOLUMES = "/Users/red/xxx/:/apk_shell"

"""
Use device name as directory to save docker_compose.yml and app.sh
Need abs path
"""
DOCKER_COMPOSE_VOLUMES = "xxx/DisCartierEJ/resources/dockercomposes/"

# logs save place in local
LOCAL_LOG_DIR = "/Users/red/xxx/logs/"
APPIUM_CARTIEREJ_LOGS_VOLUMES = LOCAL_LOG_DIR + 'RANDOM:/opt/node/CartierEJ/logs'  # RANDOM为变量在生成的过程中替换

# case to run
CASE_NAME = "test_login.py"

结果

感受

一直坚持到现在,终于要先告一个段落,感谢一直坚持的自己。第一次把自己的代码安装规范一点的样式发出来。首先,发现自己的代码能力还是弱,很多知识不熟悉。第二,写文档对自己真是一个考验,也是一种成长和反思。第三,能心无杂物的去做一件事不容易。还有,把代码拿出来分享只是一个开始和阶段总结,希望大家一起讨论。

后续文章

开源项目:移动自动化测试框架 DisCartierEJ 之 CartierEJ 介绍

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 30 条回复 时间 点赞
kasijia 回复

如果能用动态端口也是一种方式吧,很久没做这一块了,有感兴趣的同学,可以试一下。

kasijia 就小红书移动 UI 并发测试框架提点疑问 中提及了此贴 07月22日 13:35

想请教下为什么需要用到 Docker,仅仅为了省去环境搭建的诸多麻烦吗?
Appium 可以起多个服务,然后动态分配不同端口对应不同设备,最终效果上感觉没有区别。
另外即使用到了 Docker,动态生成多个 Appium 容器起服务连接设备与只生成一个 Appium 容器起多个服务连接设备,有什么区别吗?
因为没有实践过,所以有点疑问。

datafu 回复

当时没有做 ios。

ios 可以用吗

学习

terrychow 回复

都是讨论哈,大家开开心心工作,蛮好的。

刘大头 回复

嗯,我大概理解你的思路了,也有一些新想法,多谢教导先

希望大家一起努力,让测试更简单。

terrychow 回复

我们把所有的手机都放在一台 stf 上面,然后会那台机器会有一个内部 ip 地址,比如是 10.12.111.111,这样的话,每一个手机都会有一个地址。例如:10.12.111.111:7401,10.12.111.111:7409 等,再把这些信息注入到 appium 的镜像中,就可以了。如何将 stf 获取的手机信息注入到镜像中,其实是通过 docker-compose.yml 的环境变量的。下面,我会写一篇文章单独介绍这个思路。

黑水 回复

花生壳之内的估计是可以的。但是那个还没有去试。不通过域名的话,那个端口被封。

qilei 回复

思路个人觉着是一个可以试着去尝试的方向。

mark 思路不错

之前 Jenkins Master 在云上,运维帮忙做了端口映射连到内网的 Slave 上的。ngrok 或者 “花生壳” 之类的工具都可以。

simple 回复

好,谢谢提点

感谢楼主分享,赞一下开源精神。

terrychow 回复

确实不需要 root,不如你自己动手试一下,比别人告诉你的来的更受益,估计需要 5 分钟的时间吧

斯拉 回复

好,我再试试,谢谢

willys 回复

好,拜谢 orz

terrychow 回复

使用第一个方法,不需要 root。你试试就知道了。

terrychow 回复
  1. adb tcpip 5555 2.断开手机连接 输入 adb connect 3.adb devices 可以看到手机已经无线连接上了 自测小米 5 没有 root
willys 回复

好,拜谢,但上面写的还是需要 root 权限啊

willys 回复

怎么做呢,我试的时候都是说没权限开放端口,有教程不。求指教

terrychow 回复

无线连接手机不需要 root!

一直有个问题想问题楼主,无线连接的话手机一定要 root,但目前也不是所有手机能 root 吧,我看到楼主是用三星的,第二个是 appium 和手机能不同在一台电脑上进行通信吗,我不知道自己有没有看错,你的 appium 是用 docker 镜像开的吧,那对应的 ip 是宿主机 ip 还是独立 ip,如何是独立 ip 又怎么通讯,我印象中 appium 一般只会读到所在机器的设备,其他是读不到的,才疏学浅,请赐教,因为我也做了个类似的,现在卡在远程通信那里

@haifengrundadi 赞分享,继续加油

dustin 回复

希望能把思路拿出来和大家一起思考一下

感谢分享,感谢开源。。。学习了。

希望大家可以一起学习。

恒温 将本帖设为了精华贴 06月04日 18:12
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册