QUnit系列 -- 4.QUnit介绍(下)

简介:   测试用户操作   问题   那些依赖于用户操作的代码,不能通过执行函数来测试。通常元素的事件使用异步函数,例如click,这些需要模拟。   解决方案    你可以使用jQuery的 trigger()方法来触发事件,然后测试预期的行为。

  测试用户操作

  问题

  那些依赖于用户操作的代码,不能通过执行函数来测试。通常元素的事件使用异步函数,例如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大多数情况是满足要求的。

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

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

 

  保持测试原子性

  问题

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

test( "2 asserts", function() {
  var $fixture = $( "#qunit-fixture" );
 
  $fixture.append( "<div>hello!</div>" );
  equal( $( "div", $fixture ).length, 1, "div added successfully!" );
 
  $fixture.append( "<span>hello!</span>" );
  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( "<div>hello!</div>" );
  equal( $( "div", $fixture ).length, 1, "div added successfully!" );
});
 
test( "Appends a span", function() {
  var $fixture = $( "#qunit-fixture" );
 
  $fixture.append("<span>hello!</span>" );
  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" 你可以立即得到失败的测试。

  讨论

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

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

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

 

文章来源:http://qunitjs.com/cookbook/

adpics.aspx?source=kbh1983&sourcesuninfo
目录
相关文章
|
6月前
|
JavaScript 前端开发 API
SAP UI5 应用中的 datajs.js
SAP UI5 应用中的 datajs.js
44 0
|
7月前
|
Web App开发 JSON JavaScript
SAP UI5 自动化测试工具的 qunit-redirect.js
SAP UI5 自动化测试工具的 qunit-redirect.js
52 0
|
前端开发
在 ReactJS 中使用 Tailwind CSS 和 Headless UI
在 ReactJS 中使用 Tailwind CSS 和 Headless UI
365 0
讲一讲Vue+Ant Design表单验证
讲一讲Vue+Ant Design表单验证
492 1
SAP UI5 walkthrough 8 - how is component.js loaded
Created by Wang, Jerry, last modified on Nov 02, 2015
SAP UI5 component.js createContent
Created by Wang, Jerry, last modified on Mar 23, 2015
102 0
SAP UI5 component.js createContent
SAP UI5里的abap.js
Created by Wang, Jerry, last modified on Mar 03, 2016
SAP UI5里的abap.js
SAP ui5 configuration.js
Created by Wang, Jerry, last modified on May 14, 2015
SAP ui5 configuration.js
|
JavaScript 前端开发
JavaScript test framework : Mocha
Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun.
921 0

热门文章

最新文章