深度解析常用的UI自动化设计模式

下面给大家分享一下UI自动化中常用的设计模式。 由于网上已经有非常多的文章详细讲解了设计模式的编码实现,所以我今天也就不讲实现细节了。 就是讲我也讲不出什么花来,只是网上的文章基本都是讲解设计模式的本身实现,很少针对某一领域的实际场景去讲具体改怎么用设计模式。 所以今天我只针对一些实际的场景来说一下如何使用这些设计模式来完善UI自动化。

 
工厂
 
每种语言实现设计模式的方式都不一样,这里仅以java为例。Java UI代理是深入图形用户界面的编程核心,是实现组件可插入外观感受效果的有效途径。 一般来说,工厂模式是为了把创建一个对象的操作都集中在一起管理,其他所有需要用到这个对象的代码都调用工厂类来创建对象。 在UI自动化中,工厂类有一个重要的作用就是提供数据的能力。 这里直接上一个例子, 在我的项目中有这样一个场景, 我们的测试都分模块的, 不同的模块有不同的QA。 测试模型中心模块的QA想要测试的话就需要依赖建模IDE来产出各种各样的模型。 那根据上一个帖子我讲到的一个设计原则--模块间有数据依赖的时候。每个模块自己负责提供对外接口。 模型IDE的QA需要提供一个可以生产出各种不同模型的API来。 如下:
深度解析常用的UI自动化设计模式
上面我们我们用一个简单工厂来实现创建各种模型。 其他模块调用此工厂方法满足自己对模型的需求。 如果我们创建模型的类型更复杂的话,可以引入工厂模式和抽象工厂模式。 但实际上我最常用的还是简单工厂,偶尔用工厂模式抽象工厂基本没用过。使用设计模式的时候最容易出现的是过度设计, 把过于复杂的模式硬搬到项目中来。 这是不可取的。
 
那接下来说一说这个工厂存在的意义吧。 简单工厂算是设计模式里最简单的了, 简单到它几乎不是一个什么模式。 它其实只有一种思想,就是把创建一个东西的操作都统一放到一起,调用方只需要知道我要一个东西,我需要把什么参数传递进来就可以得到这个东西。 比如我们的这个例子里,调用方只需要传递我需要一个什么类型的模型的参数。 至于如何创建这个模型它不需要知道,里面包含了多复杂的UI操作它也不需要知道。 这样做的好处是:
 
代码复用,我们使用工厂的来创建的东西一般都是比较复杂的,需要很多的步骤才能创建。 如果只是随便new一下就可以得到的对象也就犯不着专门搞个工厂方法了。 如果任由写case的人根据自己的想法去创建这些对象,不仅造成了很多的重复代码。 而且这些碎片的话的代码在后期的维护上也是一个难以接受的事情。
 
封装变化,我们把创建模型的所有操作都统一放在一起。之后生产模型的操作发生变化,比如需求变动。那我们只需要改动这一处就可以了。而且调用方也完全不感知
 
解耦,就如开始说的那个设计原则一样, 调用方不感知复杂的模型生产过程, 达到解耦的作用。 在UI自动化中,尤其是业务逻辑特别复杂的大型项目中。 多人协作有个比较重要的点在这里提一下。 就是解耦,不要让其他模块的人感知自己模块的任何实现细节。 他们了解的越少,操作的越少, 出错的概率就越小,学习成本就越小。 画地为界,分而治之。 其实我个人觉得整个设计模式就是在解决两件事情:解耦和代码复用
 
单例
 
我们有了上面的工厂方法来帮助我们创建模型, 但是这里有个问题。 就是我有太多的case依赖这些模型了。 如果每个case都执行一遍上面的操作重新创建一个模型的话会有两个问题:
 
UI操作尤其耗时,尤其是生产模型这种异步操作
 
UI本就不稳定,这些重复的操作会增加case失败的概率
 
所以我们希望除了有这种创建新模型的能力之外。 还能够复用之前已经产生的模型。 于是我们就有了使用单例模式的需求。 一般提到单例模式,基本上就是懒汉式,饿汉式什么的。 但这两种大概率都是不可用的。 因为首先我们的操作是延迟加载的,只有到了使用的时候才会去UI上执行创建模型的操作。 总不能直接在类加载的时候就执行吧。 至于在不加锁的情况下判断一下对象是否为null也是不行的。 因为现在的大规模UI自动化都是并发执行的。 所以可选的方案就是加锁的双重检查机制以及静态内部类了。 这里主要讲一下静态内部类吧, 双重检查机制估计大家都玩烂了。 如下:
深度解析常用的UI自动化设计模式
静态内部类不会再LRModel的类加载的时候就加载,而是有人调用getInstance 的时候才会加载。所以保证了延迟加载
 
java 的classloader会保证静态内部类的线程安全,所以不用担心并发的问题
 
上面是静态内部类的实现方式,优点是相较于锁的双重检查方来说实现起来简单,坑少。 比如没有那个经典的指令重排序的问题。 当然缺点也明显, 就是一旦创建对象失败, 那以后就再也没有机会重新创建对象了。 而UI自动化又是出了名的不稳定。 所以还是要慎重的。
 
模板
 
模板模式在UI自动化中比较常用的原因是在产品中有很多的操作路径是复用的。 所以我们可以使用模板模式, 把固定的路径抽象出来,由子类去实现那些独立的逻辑。 比如:
深度解析常用的UI自动化设计模式