博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
QUnit系列 -- 4.QUnit介绍(下)
阅读量:4927 次
发布时间:2019-06-11

本文共 4521 字,大约阅读时间需要 15 分钟。

  测试用户操作

  问题

  那些依赖于用户操作的代码,不能通过执行函数来测试。通常元素的事件使用异步函数,例如click,这些需要模拟。

  解决方案

   你可以使用jQuery的 trigger()方法来触发事件,然后测试预期的行为。如果你不想浏览器事件被触发,你可以使用triggerHandler()来执行事件相关方法。这对于测试链接的click事件是有帮助的,因为trigger()可能会使浏览器改变地址栏信息,这恐怕不是测试过程中想要发生的。假设我们有一个简单的KeyLogger需要测试:

function KeyLogger( target ) {  if ( !(this instanceof KeyLogger) ) {    return new KeyLogger( target );  }  this.target = target;  this.log = [];   var self = this;   this.target.off( "keydown" ).on( "keydown", function( event ) {    self.log.push( event.keyCode );  });}

  我们可以手动的触发keypress事件,然后观察logger是否工作:

test( "keylogger api behavior", function() {   var event,      $doc = $( document ),      keys = KeyLogger( $doc );   // trigger event  event = $.Event( "keydown" );  event.keyCode = 9;  $doc.trigger( event );   // verify expected behavior  equal( keys.log.length, 1, "a key was logged" );  equal( keys.log[ 0 ], 9, "correct key was logged" ); });

 

  讨论

  如果你的事件处理不依赖任何特定的事件属性,你可以调用trigger(eventType)。但如果你的事件处理依赖于特殊的事件属性,你就需要使用$.Event创建一个事件对象,并设置必要的属性。对于复杂的行为触发相关事件是非常重要的,例如dragging,他由mousedown、mousemove和mouseup组成。即使是看起来很简单的事件也有可能是有很多事件组成的,例如click是由mousedown、mouseup和click组成的。你是否需要触发所有三个事件,依赖于你的测试代码,只触发click大多数情况是满足要求的。

  如果那些仍然不够,你就需要一个框架来帮你模拟用户事件了:

  •  "是一个合成的事件类库,用来处理大多数的 typing, clicking, moving 和 dragging,能准确的模拟用户的实际操作"。基于QUnit的FuncUnit使用了syn,用来对web站点做功能测试。
  •  - "一个web应用的测试工具,可以产生真正的敲击键盘,而不是简单的模拟JavaScript事件触发。允许通过敲击触发浏览器实际的事件,而这对于别的框架来说是办不到的事情"。
  •  "提供一个 API,允许测试者使用真实的、跨平台的、系统级的输入事件自动运行 UI 测试 "。他为你提供了接近真实浏览器的事件,但是要使用到 Java applets来实现。

 

  保持测试原子性

  问题

  当测试集中在一起的时候,原本应该通过的测试会失败,本该失败的测试会通过,因为之前测试的副作用,使测试结果失效。

test( "2 asserts", function() {  var $fixture = $( "#qunit-fixture" );   $fixture.append( "
hello!
" ); equal( $( "div", $fixture ).length, 1, "div added successfully!" ); $fixture.append( "hello!" ); equal( $( "span", $fixture ).length, 1, "span added successfully!" );});

  第一个append()添加了一个div,第二个equal()并没有把它考虑进去。

  解决方案

  使用test()方法保持测试的原子性,使每一个断言清洁而不存在副作用。你应该只依赖 #qunit-fixture元素内部的 fixture标签,修改和依赖其他东西将会存在副作用。

test( "Appends a div", function() {  var $fixture = $( "#qunit-fixture" );   $fixture.append( "
hello!
" ); equal( $( "div", $fixture ).length, 1, "div added successfully!" );}); test( "Appends a span", function() { var $fixture = $( "#qunit-fixture" ); $fixture.append("hello!" ); equal( $( "span", $fixture ).length, 1, "span added successfully!" );});

  QUnit会在每次测试之后重置 #qunit-fixture中的元素,移出已经存在的事件。如果你只是使用了fixture内部的元素,每次测试之后你不需要执行手工操作来保持它的原子性。

  讨论

  除了 
#qunit-fixture和过滤("高效发展"会讲到)之外,QUnit还提供了noglobals标志,看看下面的测试:
test( "global pollution", function() {  window.pollute = true;  ok( pollute, "nasty pollution" );});

  一般情况下,测试会得到成功的结果。但是选中noglobals后ok()得到失败的结果,这是因为QUnit认为他污染了window对象。在任何时候都没有必要使用那个标志,但是在整合第三方类库的时候,他对于判断是否引起全局命名污染是有帮助的。而且他也能帮助去发现由于副作用引起的bug。

 

  分组测试

  问题

  你已经分割了你所有的测试,来让他们保持原子性并不产生副作用,但是你想保证他们的逻辑可组织,它本身能以组的方式运行。

  解决方案

  你可以使用module()去把测试分组:

module( "group a" );test( "a basic test example", function() {  ok( true, "this test is fine" );});test( "a basic test example 2", function() {  ok( true, "this test is fine" );}); module( "group b" );test( "a basic test example 3", function() {  ok( true, "this test is fine" );});test( "a basic test example 4", function() {  ok( true, "this test is fine" );});

  module()后面的测试会被分在一个组里面,测试结果中每个测试的名称会被加上module名称。你还可以通过module名字选择特定测试来运行。

  讨论

  module()除了实现分组功能外,还可以用来提取通用代码,他接受一个可选的第二个参数,定义module每次运行测试开始和结束的行为。

module( "module", {  setup: function() {    ok( true, "one extra assert per test" );  }, teardown: function() {    ok( true, "and one extra assert after each test" );  }});test( "test with setup and teardown", function() {  expect( 2 );});

  你可以一起定义setup和teardown属性,或者只定义其中一个。再次调用modile()方法的时候,会重置掉之前方法定义的setup/teardown方法。

 

  高效发展(Efficient Devlopment)

  问题

  当你的测试需要运行很长时间的时候(例如好几秒),你可以不想浪费时间等待结果。

  解决方案

  QUnit有一系列的方法可以解决这个问题。最有趣的一个是点击头部的 "Hide passed tests"选项,这样QUnit会只显示失败的测试,他不会对测试时间有影响,只是起到聚焦失败测试的作用。

  另外一个有趣的特性是,QUnit会把失败的测试的名字保存在sessionStorage中(你的浏览器必须要支持),默认情况下这个特性是开启的,只是我们没有注意到他的存在。下次你再运行测试的时候,之前失败的测试会被先执行,但是他对输出结果的顺序没有影响,影响的只是执行顺序。结合使用 "Hide passed tests" 你可以立即得到失败的测试。

  讨论

  自动排序会默认发生,你以为着你的测试需要保持原子性,如果不能保证这点将会产生随机的异常。修复问题是个正确的解决方案,或者存在困难,你可以设置.reorder = false。

  除了自动排序之外,还有一些手工可选项。可以点击测试后面的"Rerun"链接,运行单个测试。他会在url中添加"testNumber=N"字符串参数,N代表你点击的测试编号。你可以重刷页面,只运行那个测试,或者使用浏览器的返回按钮区运行所有测试。

  运行module中的所有测试,几乎以相同的方式工作。除非你选择页眉右上角的module,他会在url中添加"module=N"字符串,N代表module的编号,例如:"?module=testEnvironment%20with%20object"。

 

文章来源:

转载于:https://www.cnblogs.com/softlover/archive/2012/10/29/2744067.html

你可能感兴趣的文章
软件工程心得体会
查看>>
typedef typedef struct的使用
查看>>
Log4Net各参数API
查看>>
接收发送给服务器的Post请求
查看>>
asp.net客户端IP跟踪
查看>>
前端jquery validate表单验证框架的使用
查看>>
HDU 2602 Bone Collector (01背包)
查看>>
VMware NAT端口映射外网访问虚拟机linux
查看>>
2018沈阳J How Much Memory Your Code Is Using?
查看>>
PHP连接sql server
查看>>
闭包的好处罗列
查看>>
第十六章 模板和泛型编程
查看>>
android获取手机ip
查看>>
【2016.12.03】CSS笔记
查看>>
hihocoder1766 字符串问题
查看>>
接口测试总结
查看>>
jquery.validate.js常用扩展函数
查看>>
Python标准库03 路径与文件 (os.path包, glob包)
查看>>
深入了解 Flexbox 伸缩盒模型
查看>>
排序算法之插入排序
查看>>