UI自动化Macaca-Java版实践心得

简介: #### 导语 在上篇分享中,跟大家分享了[Macaca-Java版入门指南](http://www.atatech.org/articles/61699?commentId=103931&msgid=965698#comment-103931),相信很多同学已经可以依据教程开始实践UI自动化

导语

在上篇分享中,跟大家分享了Macaca-Java版入门指南,相信很多同学已经可以依据教程开始实践UI自动化工作,但入门问题解决了,要真正在业务中实践还需要面临不少挑战,这篇文章则紧接上一篇,就Macaca在业务中的实际应用给出一些经验总结,希望能给在迷茫中不知如何入手的同学们一些方向,同时欢迎大家就本篇文章中涉及的一些方案给出更优的答案,大家一起进步。

当Macaca遭遇具体业务

1. UI控件不同平台的统一处理问题

首先,我们看一下对于单个平台,是如何做控件的查找与操作的:

    //SampleTest.java
    
    public void test() throws Exception {
        driver.elementById("targetElementId"); // elment的唯一标识
        driver.click();
    }

当平台扩展为多个时,一般来讲,如何进行同一个控件的操作呢?比如对应同一个按钮,在iOS平台,我们可以知道他的name属性,但是在安卓平台,对应的同一个控件,没有name属性,需要通过id属性来获取,那代码就会演变成如下样式:

    //SampleTest.java
    public void test() throws Exception {
        if (driver.curPlatform==PlatformType.IOS)
        {
            // 如果是iOS平台,根据name属性查找控件
            driver.elementByName("targetElementName");
            driver.click();
        } else {
            // 如果是安卓平台,根据id属性查找控件
            driver.elementById("targetElementId");
            driver.click();
        }
    }

众所周知,对于UI自动化,控件的查找是使用相当频繁的一种操作,那么问题来了,有没有一种方式,可以统一控件的查找而不必通过一个接一个的if else分支来完成呢?

2. 测试稳定性问题

测试的稳定性,是影响自动化测试的另一大因素,因为移动端操作场景的复杂性,测试用例执行的过程中可能出现多种意料之外的响应,比如点击某一个按钮,预期结果是进入下一个页面,但是却弹出了某个弹框,或者真正跳转的页面并不是我们所预期的页面,或者跳转了我们所预期的页面,但因为网络数据的加载主视图并没有刷新,这样一来,针对我们的目标页面所做的操作都会失败,因为我们无法找到预期页面的目标控件,在这种情况下,我们需要在保证预期页面已经加载的情况下再执行预期流程的用例,如何做到这一点呢?

再者,长距离到达组件入口的问题也是影响自动化稳定性的另一因素,比如我们想要测试某个基金详情页,但是要进入某个详情页,必须经过登录-首页-A页面-B页面-目标页面几个必须步骤,在到达目标页面之前的任何一个链条中出现中断,这次测试就等于无效了,这种问题怎么破?

当然,影响自动化测试稳定性的场景还有很多,这些在真正的业务实践中会逐步暴露出来,如何保证自动化测试的稳定性,是自动化测试的又一个难题。

3. 测试报告输出问题

对应每一项测试流程,执行完毕之后我们都希望能看到详尽的测试报告,如何快速高效的输出可读性强的测试报告,同样是一个必须解决的问题。

4. 学习维护成本问题

自动化平台或者工具如果对环境配置、使用规范,脚本等有较复杂要求的话,那么对于入门刚刚的测试工程师来说有一定的学习成本。另外,跟随目标产品的版本迭代,自动化脚本要做对应的调整,如果对应的调整成本比较高,也很难保证将自动化的工作方式坚持下去。

我们是如何解决这些问题的

1. 如何解决不同平台的控件统一问题

研究上面的第一个问题,我们会发现控件的获取虽然根据平台不同而需要单独处理,但是控件的获取方式其实都是统一的,获取控件有两大要素,一是获取控件的方式,比如name,id,xpath,css,class name等等,二是要获取控件的值,这个值是与获取控件的方式想对应的,针对移动端测试来说,目前一般覆盖iOS,Android两个平台,我们以这个为例,其实对于UI操作上的一个控件,提供两个平台分别的获取方式以及值就可以解决控件一致性的问题,代码如下:

    // CommonUIBean.java
    
    /**
     * 当安卓 ios两个平台对应同一控件的获取方式不一致时使用本构造函数
     * @param androidBy 获取安卓对应控件的方式
     * @param androidValue 获取安卓对应控件的值
     * @param iosBy 获取ios对应控件的方式
     * @param iosValue 获取ios对应控件的值
     */
    public CommonUIBean(GetElementWay androidBy,String androidValue,GetElementWay iosBy,String iosValue){
        this.androidBy = androidBy;
        this.androidValue = androidValue;
        this.iosBy = iosBy;
        this.iosValue = iosValue;
    }
    
    /**
     * 构造函数,用于ios&android两个平台获取UI一致的情况
     * @param commonBy 统一获取控件方式
     * @param commonValue 统一获取控件值
     */
    public CommonUIBean(GetElementWay commonBy,String commonValue){
        this.androidBy = commonBy;
        this.androidValue = commonValue;
        this.iosBy = commonBy;
        this.iosValue = commonValue;
    }

如上图这样,我们就统一了控件的一次性获取问题,通过这一层封装,如果要表示跨两个平台的一个控件,就可以简化为如下这样:

    CommonUIBean targetElement = new CommonUIBean(GetElementWay.ID,"targetElementId",GetElementWay.NAME,"targetElementName");

2. 如何保证测试稳定性

1、对于要测试的页面抽象成类,增加页面是否加载成功的逻辑,所有页面内部的测试逻辑,均在确认该页面加载成功后再执行从而保证自动化稳定性。

2.对于长距离到达组件入口的问题,通过scheme跳转解决。具体来讲,对于目标页面,只要支持scheme跳转,我们可以直接通过scheme的方式从首页直接进行加载,这样可以一步到达目标页面,省略掉了前面的诸多链路,从而保证了测试的稳定性。当然,这种方式需要依赖开发同学的支持,只有在开发层面上尽可能多的支持独立页面的scheme跳转方式,才能真正使这个解决方案大放光彩。

当然,除了这些之外,对于其他分支的阻塞场景,一方面需要我们对业务复杂度的深入了解,一方面需要在今后的实践中不断积累。

3. 如何详尽的输出测试报告

对于这个问题,我们是分这么几步走的:

1.按照业务需求将错误类型进行分类整理

2.规范化结果输出的规则

3.在对应节点按照既定规则输出日志并写入文件

这样,用例执行结束后,我们就可以看到具体的执行过程以及结果了,规范化日志输出的规则还有一个好处是便于今后结果的集成展示,比如我们要通过web直观的看到执行进度以及结果的时候,就可以通过解析日志得到相应数据。

4. 学习维护成本问题

关于学习成本,就要回到我们的标题,我们这里讲的是Macaca-Java版最佳实践,其实在最早的调研阶段,我们都是通过Javascript写用例的,但是考虑到大部分同学的学习成本,所以在Macaca支持Java后,我们立即转型到Java版本上来,这样大大减小了学习成本,另外,我们在设计自己的框架的时候,设置了config配置文件来配置通用信息,比如应用信息、用户信息等都可以通过配置文件配置,对于用例编写中常用的类进行了封装,形成了一套用例编写规范,这些对于新上手的同学都降低了接入成本,甚至对于不熟悉Java的同学,都可以比较easy的比葫芦画瓢的编写自己的用例。

关于维护成本,我们对于控件的封装使控件更新的成本变低,对于Page的封装,使得同一个页面的测试入口都集中在一起,每个页面各自维护自己的操作入口,这样当我们需要测试一个流程时,只需要把经过的页面对应的操作组装到一起就可以了,当我们需要更新某一个页面的某个操作时,只需要去页面对应的类中去修改指定的操作,而不影响原有的流程化逻辑,具体请参考源码。

Demo实例

广告时间结束,正片从这里开始。

上面讲了这么多内容做铺垫,相信很多同学已经不耐烦的想要直接看源码了,好的,这就满足泥萌。不过要成功的跑起我们的测试用例来,必须保证本机已经配置好了Macaca的相关环境,还没配置的同学请参考我上一篇文章Macaca-Java版入门指南

下载源码 github地址

$ git clone https://github.com/Yinxl/bootstrap.git

更新依赖

$ cd bootstrap
$ mvn -s settings.xml clean install

如果下载依赖过程中报错,可能是由于mvn -s命令没有生效导致的,建议将根目录下settings.xml中的依赖配置到本地Maven目录下的settings.xml中。

如何修改目标平台 ios/android?

//package com.javademo.common;
// Config.java
 // 目标平台- ios android 
   public static final String PLATFORM = "ios"; 

注意:执行iOS用例时需要将XCode升级到最新的8.1,执行用例前请先启动目标模拟器。

启动server

$ macaca server --verbose

注意启动server时不能加代理,因为server在本机启动需要连接localhost,加代理会导致无法建立连接。

执行测试用例

$ mvn test 

Demo详解

如果你成功跑起来了用例,那么下一步我们就来详细研究一下Demo的源码部分了,如果你非常不幸的因为各种原因没能run起来,请先保证Macaca的环境已经正常安装(macaca-doctor),如果环境正常但还是启动失败,请毫不吝啬的联系我。

下面给出一张各package的作用讲解,在看过这部分之后相信大部分人已经基本清楚这个框架的基础结构了,然后更深入的理解,还需要大家认真去研究一下源码。
bootstrap

To Do

1. 数据驱动实现

目前的框架已经解决了一些自动化测试用例编写中的基本问题,但是在写过一定量的case后,我们会发现case的组装实际上是一种类似的逻辑:获取控件(通过多种方式) -> 对控件进行某种操作(click)->与预期结果进行对比得到case执行结果,这有限的几种,既然这些操作如此相似,那我们是不是可以通过一种数据驱动的方式更有效的进行case的管理,就像如下这张图这样:
_2016_09_23_11_24_45
最后我们期望达到的效果是建立一个管理系统,将所有的流程通过用例管理系统进行如上信息的管理,最终实现零编码的自动化用例设计,当然这其中还需要解决诸多问题,需要我们在积累编写经验的同时不断完善。也欢迎志同道合的同学们加入到这个过程中一起努力!

2. 与网络数据的结合

想象一下我们的自动化测试工作已经正常投产,然后在运行过程中我们发现了一些bug,这时候开发就需要去解决这些bug,对于开发同学,我们现在能提供的是bug出现时的屏幕截图,但是很多时候仅仅依赖一个截图是不能帮助开发同学去定位真正的问题的,如果能获取用户当时的请求和后端的返回数据,结合屏幕截图,则能大大的方便开发同学定位并解决问题,这一步要如何实现,还需要我们进一步的思考。如果这一步完成了,那么我们相当于将线上巡检与UI自动化结合在了一起,无疑是一件很有意义的大跨越。

除了网络数据,还有很多可以和UI自动化结合的点子,比如埋点,比如监控,因为UI操作是一切app行为的基础,所以从UI自动化出发,我们有很多事情可以做,有没有热血沸腾了呢?

目录
相关文章
|
10天前
|
人工智能 JavaScript 前端开发
自动化测试框架的演进与实践###
本文深入探讨了自动化测试框架从诞生至今的发展历程,重点分析了当前主流框架的优势与局限性,并结合实际案例,阐述了如何根据项目需求选择合适的自动化测试策略。文章还展望了未来自动化测试领域的技术趋势,为读者提供了宝贵的实践经验和前瞻性思考。 ###
|
17天前
|
存储 缓存 安全
Java内存模型深度解析:从理论到实践####
【10月更文挑战第21天】 本文深入探讨了Java内存模型(JMM)的核心概念与底层机制,通过剖析其设计原理、内存可见性问题及其解决方案,结合具体代码示例,帮助读者构建对JMM的全面理解。不同于传统的摘要概述,我们将直接以故事化手法引入,让读者在轻松的情境中领略JMM的精髓。 ####
29 6
|
11天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
8天前
|
运维 监控 持续交付
自动化运维在现代数据中心的应用与实践####
本文探讨了自动化运维技术在现代数据中心中的应用现状与实践案例,分析了其如何提升运维效率、降低成本并增强系统稳定性。通过具体实例,展示了自动化工具如Ansible、Puppet及Docker在环境配置、软件部署、故障恢复等方面的实际应用效果,为读者提供了一套可参考的实施框架。 ####
|
8天前
|
运维 监控 Devops
自动化运维实践:打造高效的DevOps流水线
在软件开发的快节奏中,自动化运维成为提升效率、确保质量的关键。本文将引导你理解自动化运维的价值,通过实际案例分享如何构建一个高效、可靠的DevOps流水线。我们将从持续集成(CI)开始,逐步深入到持续部署(CD),并展示代码示例来具体说明。准备好让你的运维工作飞跃式进步了吗?让我们开始吧!
|
10天前
|
安全 Java 数据库连接
Java中的异常处理:理解与实践
在Java的世界里,异常处理是维护代码健壮性的守门人。本文将带你深入理解Java的异常机制,通过直观的例子展示如何优雅地处理错误和异常。我们将从基本的try-catch结构出发,探索更复杂的finally块、自定义异常类以及throw关键字的使用。文章旨在通过深入浅出的方式,帮助你构建一个更加稳定和可靠的应用程序。
21 5
|
12天前
|
jenkins 测试技术 持续交付
自动化测试框架的搭建与实践
在软件开发领域,自动化测试是提升开发效率、确保软件质量的关键手段。本文将引导读者理解自动化测试的重要性,并介绍如何搭建一个基本的自动化测试框架。通过具体示例和步骤,我们将探索如何有效实施自动化测试策略,以实现软件开发流程的优化。
37 7
|
10天前
|
安全 Java 程序员
Java内存模型的深入理解与实践
本文旨在深入探讨Java内存模型(JMM)的核心概念,包括原子性、可见性和有序性,并通过实例代码分析这些特性在实际编程中的应用。我们将从理论到实践,逐步揭示JMM在多线程编程中的重要性和复杂性,帮助读者构建更加健壮的并发程序。
|
13天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
38 5
|
15天前
|
机器学习/深度学习 人工智能 自然语言处理
智能化软件测试:AI驱动的自动化测试策略与实践####
本文深入探讨了人工智能(AI)在软件测试领域的创新应用,通过分析AI技术如何优化测试流程、提升测试效率及质量,阐述了智能化软件测试的核心价值。文章首先概述了传统软件测试面临的挑战,随后详细介绍了AI驱动的自动化测试工具与框架,包括自然语言处理(NLP)、机器学习(ML)算法在缺陷预测、测试用例生成及自动化回归测试中的应用实例。最后,文章展望了智能化软件测试的未来发展趋势,强调了持续学习与适应能力对于保持测试策略有效性的重要性。 ####