用java构建企业级自动化框架(首篇-制定测试者使用语言3)_eclipse自动化用企业级的吗-程序员宅基地

技术标签: 语言  java  行业应用  selenium  测试  编程语言  框架  

这个是我后来写的一本书,http://www.ituring.com.cn/minibook/10775。这个是我后来找到的自动化完美解决方案。


接下来对数据库的测试也提供一种编写思路,具体如何实现这个就不细说了。

     <Status name='get_ponumber' expected='0' timeout="600" compare="&gt;">

<Sql name="sql_ponum" db_type="oms_ff" params="testjingdongcom.productId">


SELECT DISTINCT p.po_no FROM wff_po_line p, wff_line_item l WHERE p.co_order_no=[orderNo]

AND l.order_no = p.co_order_no AND l.item_id = :1 AND l.line_no = p.co_line_no


                </Sql>

</Status>


当然,除了页面操作和数据库以外,自己系统特有的业务也可以自己定义并自动化,比如jms远程调用,发邮件文件短线等等。

说了这么多,大家有没有发现这种类型脚本有一个问题,他们执行的每一个节点都是一个类,而测试人员写这脚本的时候,可能还需要开发人员告诉他们这些类是干什么的,传哪些参数。测试人员没有主动权在脚本中编写自己的流程步骤。因为流程都封装在类里面的方法里,同时,把流程步骤封装到java类里会出现类和包越来越膨胀。到最后可能会膨胀到无法维护。那怎么样才能解决这些问题呢,那就是以把操作的流程步骤到放在脚本里面去。而不是java类里。

下面给出一个思路,每个java类只执行一个原子操作,如何组装这些原子操作是放在脚本里面去执行的。


先看代码


第一,我先定义一个执行类负责执行页面操作流程的所有方法,比如点击,输入,选择等等。


public class ActionExecutor {






private static Map<String, Selenium> browsers = new HashMap<String, Selenium>();


private static Selenium getBrowser() {
String threadName = Thread.currentThread().getName();
Selenium browser = browsers.get(threadName);
return browser;
}


public static Selenium getSelenium() {
Selenium browser = getBrowser();
return browser;


}


public static void open(String url, String tip) {
Selenium browser = getBrowser();
if (browser != null) {
try {
browser.open(url);


browser.waitForPageToLoad(String
.valueOf(LambConstants.DEFAULT_TIMEOUT));
browser.windowMaximize();
} catch (Exception e) {
testLog.info("open page==> url=" + url + " couldn't open-->"
+ tip);
}
}
}


public static void type(final String locator, final String value,
final String tip) throws Exception {
Poller.until(new Condition() {


public void doCommands() {
Selenium browser = getBrowser();
log.debug("type command locator=" + locator);
if (browser != null) {
try {
browser.type(locator, value);
testLog.info("input command==> value=" + value
+ " input to TextArea " + locator
+ " success-->" + tip);
logger.info("LogBaseTest");
} catch (Exception e) {
testLog.info("iput command==> value=" + value
+ " input to TextArea " + locator
+ " failure-->" + tip);
}
}
}


});
}


public static void click(String locator, String tip) {
Selenium browser = getBrowser();
if (browser != null) {
log.debug("click command locator=" + locator);
try {
browser.click(locator);
testLog.info("click Button==> locator=" + locator
+ " execute success-->" + tip);
} catch (Exception e) {
testLog.info("click Button==> locator=" + locator
+ " execute failure-->" + tip);
}
}
}


public static void clickAndWait(String locator, String timeout, String tip) {
Selenium browser = getBrowser();
if (browser != null) {
log.debug("click and wait command locator=" + locator);
try {
browser.click(locator);
browser.waitForPageToLoad(timeout);
testLog.info("click Button==> locator=" + locator
+ " execute success-->" + tip);
} catch (Exception e) {
testLog.info("click Button==> locator=" + locator
+ " execute failure-->" + tip);
}
}
}

这里是只实现一部分selenium的操作。

那现在我们如何使用它呢?

第一,开发的老规矩,先定义一个接口去制定类的行为。


public interface Action {

public void validate() throws Exception;

public Object execute() throws Exception;
}


好的,下面就简单了,去实现它的所有实现类

比如click等等

public class ClickAction  implements Action {


private String locator;

public Object execute() throws Exception {
ActionExecutor.click(locator,tip);
return null;
}


public void validate() throws Exception {
}


public String getLocator() {
return locator;
}


public void setLocator(String locator) {
this.locator = locator;
}
}


比如选择

public class SelectAction implements Action{
private String locator;
private String value;
public void validate() throws Exception {

}


public Object execute() throws Exception {
ActionExecutor.setSelect(this.locator, this.value);
return null;
}


public String getLocator() {
return locator;
}


public void setLocator(String locator) {
this.locator = locator;
}


public String getValue() {
return value;
}


public void setValue(String value) {
this.value = value;
}



}


这时候你看下面调用脚本,即xml,会发现所有调用流程是放在xml去执行的。(脚本的执行方法和前面说的反射执行方式是一样的)

<StartBrowserAction/>
<OpenAction url="http://www.google.com.hk"/>
<TypeAction locator="q" value="java"/>
<TypeAction locator="q" value="C++"/>
<SleepAction seconds="5"/>

             <ClickAction locator="btnG"/>

<StopBrowserAction/>


这样就把调用逻辑写在脚本里面去了,当然这里面还有些难点,比如把流程封装在代码中非常容易实现的if 选择和for循环在这里是如何实现。对各种java类库比如字符串方法的使用能否做到和程序员写代码一样方便都应该考虑进去。


好的,我们把这两种方法脚本写法比较一下分析它们的优缺点,

1,流程封装到java类里,各种逻辑和技术等容易在代码中实现,但会造成java类膨胀,此框架会和测试人员分离,测试人员无法使用,最后要想使用好这个框架只能是java开发人员。也间接造成自动化组人员膨胀。


2,流程以原子操作供脚本调用,即流程写在脚本文件里,这时脚本对测试人员透明,测试人员可写脚本改脚本,测试人员对此框架掌握使用权。但一些java类中很容易实现的分支循环和字符串操作等等此时在脚本里实现难度就会加大。

后记,最近一些研究。


那有没有更好的方法呢,有,但这种方法有点脱离java范畴。在一些公司,他们的脚本语言不是xml 而是用python 和 ruby语言去写脚本,脚本写完直接运行这些脚本。这样所有问题都能解决。此时只有一个问题,python和ruby使用者在中国并不广泛。很多时候只能找java开发人员培训后去写这些脚本,此外,java开发人员愿不愿意写这些测试脚本也是一个问题。


python 和 ruby是一种解释性强的脚本语言,这也注定用它这种语言在开发一种供测试人员使用的语言也比较简单。比如DSL(领域特定语言)具体怎么创建就不说了,网上有很多实例。

当然对于java框架来说,最好的实现方法是用ruby等脚本语言创建DSL,编译后能在java虚拟机里执行就最好了,这样就可以实现在java里使用领域特定语言。比如使用xruby等等。但因为在后面谈到并发分布式执行等等,而这些java有自己的优势。所以主框架语言建议应该选用java。


好了,借花献佛,看下覃其慧所著的文章,熟悉下 DSL语言的脚本。


让测试的描述能够接近被测系统的领域语言、使测试意图得到清晰表达就是我们想要得到的效果。DSL正好能够帮我们实现。

让我们再看看之前的那段代码:

selenium.open(“/”)
selenium.type(“id=username”, “myname”)
selenium.type(“id=password”, “mypassword”)
selenium.click(“id=btnLogin”)
selenium.waitForPageToLoad(30000)
assertTrue(selenium.isTextPresent(“Welcome to our website!”))

由于使用的是通用语言,在我们这个特定的使用场景中显得过于细节化、过程化,不能清晰表达测试意图。

换成DSL,我们的测试就可以直接用验收标准的语言来描述如下:

Given I am on login page
When I provide username and password
Then I can enter the system

这样测试的内容就直观多了,还包含了一些业务信息,让我们知道这个是在测试一个登录的场景,而不是任意的输入信息,兼顾传递了业务知识的职责。至于这些DSL背后能够运行的代码,也被隐藏起来。如果是不能够阅读原来那样的测试代码的人(不管是需求分析人员还是客户甚至一些对自动化代码关注比较少的测试人员)想要加入到自动化测试活动中进行反馈,就不会被DSL背后的代码带来的“噪音”所影响。

当然,在我们的现实应用场景中,这个需求没有那么简单,我们的验收标准还会考虑不同的数据比如输入不同组合的用户名密码:

Given I am on login page
When I provide ‘david’ and ‘davidpassword’
Then I can enter the system
Given I am on login page
When I provide ‘kate’ and ‘kate_p@ssword’
Then I can enter the system

以及更多的测试数据。

那么这种情况下,仅仅是比较通俗的语言还是不够的,毕竟测试数量在那摆着。如果测试数量不能减少,维护起来仍然很麻烦。打个比方,如果系统的实现变成了每次都要输入用户名、密码和一个随机验证码,我们就需要在我们的自动化测试中修改多处,比较繁琐。因此,我们需要在可读性比较好的自然语言描述的测试上,把它的抽象层次再提高一点。

幸运的是,我们当时选择的DSL工具是cucumber,它除了提供了几个测试的描述层次:Feature,Scenario,Steps,还提供了非常好的一种组织方式—数据表。

这样,我们的这个自动化测试就可以把之前的那个登录的功能根据特性、场景总结和具体的步骤分离开来,清晰的分层,同时利用数据表我们的测试精简成一系列被重复多次但输入数据有所变化的操作过程,如下:

Feature: authentication
In order to have personalized information
I want to access my account by providing authentication information
So that the system can know who I am
Scenario Outline: login successfully
Given I am on login page
When I provide ‘<username>’ and ‘<password>’
Then I can enter the system
Examples:
|username |password |
|david |davidpass |
|kate |kate_p@ssword|

测试这下看起来就更清爽了。首先,用Feature关键字,我们把测试分类到login这个大特性下的,并对这个特性本身的业务目的进行相关描述,带进业务目标,传递业务知识;然后用Scenario关键字来提高挈领的标明我们这个测试场景中做的是测试登录成功的情况,并且把步骤都写出来;最后,我们用Examples关键字引出具体的数据表格把用到的数据都展示出来,避免我们的相同步骤因为测试数据的变化而重复若干遍造成冗余。万一碰上了需求的变化,要求同时提供用户名、密码和验证码,那我们的测试也只需要改动较少的地方就足够了。

更棒的是,用了这种数据表的方式,整个团队的协作效率提高了。对于写代码没有那么顺畅的测试人员来说,增加自动化测试也就是增加更多测试数据,填充到数据表里就可以了。




 





版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xhyspring/article/details/6994450

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签