一、robot简介

  robot是dojo框架中用来进行前端自动化测试的工具,doh主要目的在于单元测试,而robot可以用来模仿用户操作来测试UI。总所周知,Selenium也是一款比较流行的前端自动化测试工具,与Selenium相比robot的优点在于robot触发的浏览器事件是真正的用户操作事件,而Selenium中的事件属于“合成事件”。打个比方,用户在一个textbox元素上触发了mousedown事件,但是在触发mousedown事件之前,肯定会触发mouseover等事件。如果使用Selenium的工具的“合成事件”则不会触发mouseover等事件。对于使用dojo框架的开发者来说,robot更有利于同dijit交互,包括自定义dijit;当然最重要的一点是,在研究selenium的过程中,我发现Selenium有严重的浏览器兼容性问题!于是果断放弃。

  言归正传,下面来具体介绍robot。robot主要有三部分组成:

  doh/robot,这里面包含的是robot的核心内容,与dojo框架没有耦合关系,可以单独拿出去作为一个自动化测试工具。

 require(["doh/robot"], function(doh){
...
});

  dojo/robot,该模块使用dojo核心技术,支持doh/robot的全部方法,主要在doh/robot的基础上增加了两个方法:mouseMoveAt和scrollIntoView。

 require(["dojo/robot"], function(doh){
...
});

  dojox/robot,该模块在dojo/robot的基础上增加了两个重要方法:initRobot和waitForPageLoad。为什么说他们重要,因为他们可以再一个测试案例文件中控制其他的测试文件,后文将详细。

 require(["dojox/robot"], function(doh){
...
});

  

  二、基本步骤

  doh/robot测试主要分为以下四步:

  1、实例化一个doh.Deferred对象

  2、执行交互命令

  3、设置一个超时函数来验证交互结果

  4、在runTest中返回deferred对象

  这个事例中页面上一个文本输入框,包含hi两个字符,然后模仿用户输入“ again”动作。示例,robot实际上是一个applet第一次访问的话会提示安装。

 require(["doh/runner", "doh/robot"], function(doh, robot){
doh.register("doh/robot",
{
name: "dojorobot1",
timeout: 6900,
setUp: function(){
document.getElementById('textbox').value="hi";
},
runTest: function(){
var d = new doh.Deferred();
robot.mouseMove(30, 30, 500);
robot.mouseClick({left:true}, 500);
robot.typeKeys(" again", 500, 2500);
robot.sequence(d.getTestCallback(function(){
doh.is("hi again", document.getElementById('textbox').value);
}), 900);
return d;
}
});
doh.run();
});
    <form>
<input type="text" value="hi" id="textbox" style="position:absolute; left:0px; top:20px; font-family:system;"></input>
</form>

  这里要说以下robot.sequence和d.getTestCallback这两个函数,sequence是robot中的一种同步方式书写的setTimeout,下文delay中会讲到这类方法的优势。doh.Deferred是doh中对dojo/Deferred的扩展,加入了许多方法,getTestCallback就是其中之一,该函数作用就在于交互命令执行完成后验证交互结果,并将结果告知测试框架从而决定显示绿条还是红条,通常一个测试案例中只有一处调用该方法。一下是该函数的源码:

 getTestCallback: function(cb, scope){
var _this = this;
return function(){// 该函数返回一个闭包给sequence函数,从而在一定时间后调用该闭包
try{// 执行验证函数,监控结果,并将结果通知测试框架
cb.apply(scope||doh.global||_this, arguments);
}catch(e){
_this.reject(e);// 红条
return;
}
_this.resolve(true);// 绿条
};
},

  

  三、API介绍

  1、基本参数

  下面以doh/Robot中typeKeys为例介绍一下robot API的基本参数,具体提供了哪些API可以在这里查看:API

 typeKeys: function(/*String||Number*/ chars, /*Integer, optional*/ delay, /*Integer, optional*/ duration){
// summary:
// Types a string of characters in order, or types a dojo.keys.* constant.
//
// description:
// Types a string of characters in order, or types a dojo.keys.* constant.
// Example: robot.typeKeys("dijit.ed", 500);
//
// chars:
// String of characters to type, or a dojo.keys.* constant
//
// delay:
// Delay, in milliseconds, to wait before firing.
// The delay is a delta with respect to the previous automation call.
// For example, the following code ends after 600ms:
// robot.mouseClick({left:true}, 100) // first call; wait 100ms
// robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
//
// duration:
// Time, in milliseconds, to spend pressing all of the keys.
//
}

  delay,顾名思义目的在于延迟,在webAPP中经常会有动画效果,等待动画结束后在执行click等事件,所以每一个API中与UI交互的函数都会提供这个方法。该方法内部使用setTimeout方法实现,既然这样,为什么不让用户直接使用setTimeout方法?原因在于dojo可以为我们自动调整一系列动作的执行顺序及间隔。举个例子,如果使用setTimeout,动作f1需要在300ms后执行,动作f2需要在f1之后100ms执行那就需要设置f2的timeout时间为400ms,这时候f1之前要加一个动作f3在f1之前200ms执行,

现在我们就需要挨个该f1跟f2的时间参数,如果f1之后有100个动作要执行。。。。God bless you。使用robot API提供的函数,我们只需要设置每个动作之间的时间间隔即可。

     setTimeout(f1, 300);
setTimeout(f2, 400);
=>>
setTimeout(f3, 300);
setTimeout(f1, 500);
setTimeout(f2, 600);
     var mask = query("div.ovwHighlight")[0];
robot.mouseMoveAt(mask, 200, 200);
robot.mousePress({left: true}, 100);
robot.mouseMoveAt(mask, 200, 200, 10, 10);
robot.mouseRelease({left: true}, 100);

  duration便是的是执行这个动作所需要的时间,以typeKeys为例,假设duration设置为1800ms,char为“abc”,则输入a、b、c这三个字符各占600ms。

  2、mouseMoveAt

  dojo/Robot中提供了一个mouseMoveAt函数,在上文的示例中,我们可以看到鼠标移动函数用的是mouseMove函数,该函数与mouseMoveto函数都是通过相对于当前浏览器document的x、y坐标来定位元素,而mouseMoveAt则是通过选择符或者node节点来定位元素。

 mouseMoveAt : function(/*String||DOMNode||Function*/ node, /*Integer, optional*/ delay, /*Integer, optional*/ duration, /*Number, optional*/ offsetX, /*Number, optional*/ offsetY){
// summary:
// Moves the mouse over the specified node at the specified relative x,y offset.
//
// description:
// Moves the mouse over the specified node at the specified relative x,y offset.
// You should manually scroll off-screen nodes into view; use dijit.robot for automatic scrolling support.
// If you do not specify an offset, mouseMove will default to move to the middle of the node.
// Example: to move the mouse over a ComboBox's down arrow node, call doh.mouseMoveAt(dijit.byId('setvaluetest').downArrowNode);
//
// node:
// The id of the node, or the node itself, to move the mouse to.
// If you pass an id or a function that returns a node, the node will not be evaluated until the movement executes.
// This is useful if you need to move the mouse to an node that is not yet present.
//
// delay:
// Delay, in milliseconds, to wait before firing.
// The delay is a delta with respect to the previous automation call.
// For example, the following code ends after 600ms:
// doh.mouseClick({left:true}, 100) // first call; wait 100ms
// doh.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
//
// duration:
// Approximate time Robot will spend moving the mouse.
// The default is 100ms.
//
// offsetX:
// x offset relative to the node, in pixels, to move the mouse. The default is half the node's width.
//
// offsetY:
// y offset relative to the node, in pixels, to move the mouse. The default is half the node's height.
//

  所以上文中的实例可以这样写:

 require(["doh/runner", "dojo/robot"], function(doh, robot){
doh.register("doh/robot",
{
name: "dojorobot1",
timeout: 6900,
setUp: function(){
document.getElementById('textbox').value="hi";
},
runTest: function(){
var d = new doh.Deferred();
robot.mouseMoveAt(document.getElementById('textbox'), 500);
robot.mouseClick({left:true}, 500);
robot.typeKeys(" again", 500, 2500);
robot.sequence(d.getTestCallback(function(){
doh.is("hi again", document.getElementById('textbox').value);
}), 900);
return d;
}
});
doh.run();
});

  3、initRobot

  对于WebAPP来说,都需要将测试代码与主程序代码分离。但测试文件执行时需要与主程序中的UI交互,这时轮到initRobot闪亮登场了。该函数位于dojox/Robot中,所以我们需要引入dojox/Robot。initRobot主要的作用就在于将当前测试文件的执行环境转变为主程序环境,这时robot.doc、robot.window代表的则是主程序中的document和window。比如说你想使用document.getElementById(‘login')来获取主程序中的login元素,那么你需要这样来写robot.doc.getElementById('login'),官方文档中提到使用dojo模块中的方法的执行环境都是主程序环境,遗憾的是我在实际使用中发现并非如此,有的模块方法的确是主程序环境比如query,而有的则并非主程序环境比如registry。

  具体示例可以访问这里,查看源码你会发现这里面并没有robot的测试代码,该文件位于dojo-release-1.9.1-src\dijit\tests目录下,robot测试代码位于dojo-release-1.9.1-src\dijit\tests\robot目录下。

参考文档:https://dojotoolkit.org/reference-guide/1.9/util/dohrobot.html#doh-robot

下一篇我们将具体看一个完整robot示例,以及将robot与selenium联合使用进而将他与CI工具集成。同时我们还会讨论robot异步函数的美中不足。

前端自动化测试工具doh学习总结(二)的更多相关文章

  1. 前端自动化测试工具doh学习总结(一)

    前言 项目中需要用到前端自动化测试,自己被当作一个探针研究了下目前用的比较多的web自动化测试工具.一开始研究的是的selenium,但由于项目使用了大量的dijit控件,写起testCase来很费劲 ...

  2. selenium + python自动化测试unittest框架学习(二)

    1.unittest单元测试框架文件结构 unittest是python单元测试框架之一,unittest测试框架的主要文件结构: File >report >all_case.py &g ...

  3. 前端模块化工具--webpack学习心得

    话说前头 webpack前段时间有听说一下,现在已经到了3.x的版本,自己没去接触.因为之前使用gulp来作为自己的项目构建工具.现在感觉gulp使用的趋势在减少.现在这段时间去接触了webpack, ...

  4. 前端自动化测试工具--使用karma进行javascript单元测试(转)

    Karma+Jasmine+PhantomJS组合的前端javascript单元测试工具. 1.介绍 Karma是由Google团队开发的一套前端测试运行框架,karma会启动一个web服务器,将js ...

  5. commons-lang3工具类学习(二)

    三.BooleanUtils 布尔工具类 and(boolean... array) 逻辑与 BooleanUtils.and(true, true)         = true    Boolea ...

  6. java 编写小工具 尝试 学习(二)

    1. 新建一个窗口  ,代码 如下 ,截图 如下 package jFrameDemo; import javax.swing.JFrame; import javax.swing.WindowCon ...

  7. nightwatch-前端自动化测试工具安装

    最近再弄这个前端自动化测试工具,刚开始弄了几天,目前为止遇到很多坑,光是安装就费了不少时间,记录一下,以便自己忘记. 这里是它的官网,目前没找到中文版的官网,全英文,对我这个英语渣来说有点难理解. 一 ...

  8. WebDriver自动化测试工具(1)---环境搭建

    Webdriver是一个前端自动化测试工具,可以模拟用户点击链接,填写表单,点击按钮等操作,下面介绍其使用 一.下载WebdriverC#类库以及对应浏览器驱动 http://www.selenium ...

  9. 前端见微知著工具篇:Grunt实现自动化

    转载说明 本篇文章为转载文章,来源为[前端福利]用grunt搭建自动化的web前端开发环境-完整教程,之所以转载,是因为本文写的太详细了,我很想自己来写,但是发现跳不出这篇文章的圈子,因为写的详尽,所 ...

随机推荐

  1. 【redis】redis 在 windows 下安装使用

    1.安装 windows 下 redis 可用客户端 : http://redisdesktop.com/download ; 或在 github 上下载 redis zip 包,解压包到某个目录并在 ...

  2. 用Backbone.js创建一个联系人管理系统(四)

    原文: Build a Contacts Manager Using Backbone.js: Part 4 这一系列教程的第四部分,教我们如何完成对已经存在的Contacts进行编辑和保存. 本教程 ...

  3. 【Java】使用iText生成PDF文件

    iText介绍 iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML.Html文件转 ...

  4. 大前端学习笔记整理【四】LESS基础

    第一次接触CSS预编译,然后对比后发现其实less的上手容易度确实比sass高不少,再加上公司项目也是使用的less.所以想想还是根据网上的各种教程,整理出来了一些比较基础的.而且比较能让我们这种初学 ...

  5. js 有用的代码

    1. 如何创建嵌套的过滤器: //允许你减少集合中的匹配元素的过滤器, //只剩下那些与给定的选择器匹配的部分.在这种情况下, //查询删除了任何没(:not)有(:has) //包含class为“s ...

  6. js中返回上一页失效的解决办法

    最近在做移动端的时候,碰到了一个问题,就是点击返回按键,使用history.go(-1)或history.back(-1)不能够生效.于是便寻找其他的方法,终于找到了一位大神的方法如下: if(win ...

  7. PHP 定界符使用

    在PHP代码中,如果不想一行一行的拼接HTML或者JS的话,那么使用定界符将是最好的帮手! 使用方法: <<<eof .......html/js..... eof; 注意事项:(别 ...

  8. [fortify] preg_replace命令注入

    慎用preg_replace危险的/e修饰符(一句话后门常用) 作者: 字体:[增加 减小] 类型:转载 时间:2013-06-19我要评论 要确保 replacement 构成一个合法的 PHP 代 ...

  9. PHP限制提现时间-----周一至周五 9点到17点

    $time = time(); $err_msg = '请在周一至周五 9:00-17:00 提交申请!'; $week = date('w', $time); $hour = date('H', $ ...

  10. VS2015调试UWP程序时提示错误DEP0700 : Registration of the app failed. Another user has already installed

    在同一台windows10电脑上调试过一个工程以后,切换了账号再次调试出现错误 DEP0700 : Registration of the app failed. Another user has a ...