# 开源项目:移动自动化测试框架 DisCartierEJ 之 CartierEJ 介绍
@ author Juan Liu
@ Date 2017/06/04
在使用 DisCartierEJ 进行 Case 使用的时候,我们需要编写自己的 Case,而对 Case 的编写是有要求的,这个要求并不是说,有额外的难度(相反可能是降低了难度)。主要是因为在 DisCartierEJ 从 STF 获取 devices 信息注入(render)到 docker_compose.yml 模块中生成每一个设备对应的 docker_compose.yml,也就是注入到容器的环境变量中。而 case 需要将这些信息从环境中读取出来,这个时候就需要将相关的参数对应,而 CartierEJ 可以很好的获取这些信息。下面会仔细讲解这个方面。
DisCartierEJ 和 CartierEJ 的关系是既不充分也不必要关系,只是两者结合可以更好的使用。
CartierEJ 是一个尝试将移动 UI 自动化,进行规范化编写的” 微框架 “,以便于开发者可以很简单地开发。开发者只要按照已有的模板进行复制,修改就可以,增加效率,降低了成本。
CartierEJ 的目标是建立一个移动 UI 自动化开发模板。希望将开发测试工程师开发 case 的时间降低到半天以内(甚至半小时以内)。
CartierEJ 主要分为以下几个部分,PV、Action、Utility、Test 三个部分。
white_list 这个模块要单独强调一下。在我们进行流程 case 运行的过程中,会出现一些额外的情况,比如出现更新框,出现弹框等,这个其实不是错误,但是会影响流程的执行。这个时候,我们做了一个白名单去处理这些情况,避免了额外的报错。
比如,有的 app 会出现更新按钮框。这个时候,我们在白名单中如果已经包含了处理这个更新按钮,那么我们会点掉这个更新框,并将图截下来保存,然后继续执行。
Test 模块,主要运行 case 的地方。
上图是框架的大概结构。
下图是实际的项目结构。
本地 case 代码要和 Appium 进行交流,需要 desired_capabilties。在 DisCartierEJ 中的 case 代码是在 docker 的 appium_cartierej_anriod 的镜像里。这个时候,我们需要将从 stf 获取的信息传递给 case,然后 case 得到整个信息和 appium 进行通信。
两者的通信,我们是通过,环境变量来实现的。这个可以从 CartierEJ 下 tests 的 conftest.py 文件可以得到。
@pytest.fixture(scope="session")
def desired_caps(request):
"""
Used to test multi devices
"""
desired_caps = defaultdict(list)
desired_caps['platformName'] = 'Android'
try:
version = os.environ.get("PLATFORM_VERSION")
app_name = os.environ.get("APK_NAME")
devices_name = os.environ.get("DEVICES_NAME")
except KeyError:
logger.error("No environment variables for desired caps")
return None
if version is None or app_name is None or devices_name is None:
return None
desired_caps['platformVersion'] = version
desired_caps['app'] = app_name
desired_caps['deviceName'] = devices_name
desired_caps['newCommandTimeout'] = os.environ.get("NEW_COMMAND_TIME_OUT")
desired_caps['unicodeKeyboard'] = True
desired_caps['resetKeyboard'] = True
desired_caps['noReset'] = False
return desired_caps
下面我们用一个实例来说明。
图中红色框框,就是一个手机需要的基本信息。这些信息需要从 stf 上获取。
def get_stf_devices(cond=None):
"""
According conditions to filter devices on STF and return
:param cond: conditions to filter devices
:return: list of devices meeting conditions
"""
logging.info("Get devices from stf platform.")
http_stf = Selector(url=v.STF_URL, token=v.TOKEN)
http_stf.load()
devices = http_stf.find(cond).devices()
logger.info("Devices length is : " + str(len(devices)))
return devices
其中的 cond 语句如何编写大家可以参考使用 stf_selector 对 stf 的刷选,这个工具语法非常简单。
cond = (where("present").exists()) \
& (where("abi").exists()) \
& (where("using").exists()) \
& (where('present') == True) \
& (where('using') == False)
devices = get_stf_devices(cond=cond)
这里的条件如下,然后我们就可以得到 devices 信息。然后 render 到模块中。主要的步骤就是先使用 docker_composes_data,在使用 generator_docker_composes 方法即可。
最后会在 resources/dockercomposes 文件夹下生产各个设备的 docker_compose.yml。
结果如下:
version: '2'
services:
appium:
image: suifengdeshitou/appium-cartierej-android:latest
container_name: cdf1b667
environment:
- APK_NAME=/apk_shell/com.xingin.xhs-test-4.20.apk
- PLATFORM_VERSION=5.0
- DEVICES_NAME=xxx.xxx.xxx.xxx:7641
- MOBILE_PHONE_NUMBER=xxxxxxxxxxx
- NEW_COMMAND_TIME_OUT=60
- CODE=xxxx
ports:
- "4723"
command: "bash /app_shell/app.sh"
volumes:
- /Users/red/tmp/logs/cdf1b667:/opt/node/CartierEJ/logs
- /Users/red/PycharmProjects/DisCartierEJ/resources/dockercomposes/cdf1b667:/app_shell
- /Users/red/temp/appium:/apk_shell
这个时候就会在每一个启动的容器内把设备的信息设置为环境变量。这个时候,case 中的代码就会去取这些环境变量然后得到设备信息,然后连接 appium 进行交互。
以上就是 DisCartierEJ 与 CartierEJ 之间的信息传递过程
GitHub 上的 CartierEJ 只有 Native 的代码,在实际的过程中还需要 webview 相关的部分(在小红书内部已经基本实现了)。未来会慢慢地提交上去。
自己想的和写出来的还是有点不一样的,写的要求更高,如果有不懂的地方,希望大家回复我。
之前的 DisCartierEJ,由于自己是新手,有个模块的功能有缺陷,不过已经修改了,如果之前你 fork 了,可以重新 fork 一下。