使用 QUnit 测试 JavaScript 代码:分步指南

qunit 由 jquery 团队开发,是一个用于对 javascript 进行单元测试的出色框架。在本教程中,我将介绍 qunit 具体是什么,以及为什么您应该关心严格测试您的代码。

什么是 QUnit

QUnit 是一个强大的 JavaScript 单元测试框架,可以帮助您调试代码。它由 jQuery 团队成员编写,是 jQuery 的官方测试套件。但 QUnit 足够通用,可以测试任何常规 JavaScript 代码,甚至可以通过某些 JavaScript 引擎(如 Rhino 或 V8)测试服务器端 JavaScript。

如果您不熟悉“单元测试”的概念,请不要担心。理解起来并不难:

在计算机编程中,单元测试是一种软件验证和确认方法,程序员在其中测试源代码的各个单元是否适合使用。单元是应用程序的最小可测试部分。在过程式编程中,一个单元可以是一个单独的函数或过程。

此内容引自维基百科。简而言之,您为代码的每个功能编写测试,如果所有这些测试都通过了,您可以确定代码将没有错误(主要取决于您的测试的彻底程度)。

立即学习“Java免费学习笔记(深入)”;

为什么应该测试代码

如果您以前没有编写过任何单元测试,您可能只是将代码直接应用到网站上,点击一会儿看看是否出现任何问题,并在发现问题时尝试修复它。这种方法存在很多问题。

首先,这非常乏味。点击实际上并不是一件容易的事,因为你必须确保所有内容都被点击,并且很可能你会错过一两件事。其次,您为测试所做的一切都不可重用,这意味着找到回归并不容易。什么是回归?想象一下,您编写了一些代码并对其进行了测试,修复了发现的所有错误,然后发布了它。然后,用户发送一些有关新错误的反馈,并请求一些新功能。您返回代码,修复这些新错误并添加这些新功能。接下来可能发生的是一些旧的错误再次出现,这被称为“回归”。看,现在你必须再次点击,很可能你就不会再发现这些旧的错误了;即使你这样做了,你也需要一段时间才能发现问题是由回归引起的。通过单元测试,您可以编写测试来查找错误,一旦代码被修改,您可以再次通过测试对其进行过滤。如果出现回归,某些测试肯定会失败,并且您可以轻松发现它们,知道代码的哪一部分包含错误。由于您知道刚刚修改的内容,因此可以轻松修复它。

单元测试的另一个优点尤其适用于 Web 开发:它简化了跨浏览器兼容性的测试。只需在不同的浏览器上运行测试,如果一种浏览器出现问题,您可以修复它并再次运行这些测试,确保它不会在其他浏览器上引入回归。一旦所有目标浏览器都通过测试,您就可以确定它们都受支持。

我想提一下 John Resig 的项目之一:TestSwarm。通过使其分布式,它将 JavaScript 单元测试提升到一个新的水平。这是一个包含许多测试的网站,任何人都可以去那里,运行一些测试,然后将结果返回到服务器。这样,代码就可以非常快速地在不同浏览器甚至不同平台上进行测试。

如何使用 QUnit 编写单元测试

那么到底如何使用 QUnit 编写单元测试呢?首先需要搭建测试环境:

QUnit Test Suite

QUnit Test Suite

    登录后复制

    正如您所看到的,这里使用了 QUnit 框架的托管版本。

    要测试的代码应放入 myProject.js,并且您的测试应插入 myTests.js。要运行这些测试,只需在浏览器中打开此 HTML 文件即可。现在是时候编写一些测试了。

    单元测试的构建块是断言。

    断言是预测代码返回结果的语句。如果预测是错误的,则断言失败,并且您知道出了问题。

    要运行断言,您应该将它们放入测试用例中:

    // Let's test this functionfunction isEven(val) {return val % 2 === 0;}test('isEven()', function() {ok(isEven(0), 'Zero is an even number');ok(isEven(2), 'So is two');ok(isEven(-4), 'So is negative four');ok(!isEven(1), 'One is not an even number');ok(!isEven(-7), 'Neither is negative seven');})

    登录后复制

    这里我们定义了一个函数 isEven,它检测一个数字是否为偶数,我们想测试这个函数以确保它不会返回错误的答案。

    我们首先调用test(),它构造一个测试用例;第一个参数是将在结果中显示的字符串,第二个参数是包含我们的断言的回调函数。一旦 QUnit 运行,就会调用此回调函数。

    我们编写了五个断言,所有断言都是布尔值。布尔断言期望其第一个参数为 true。第二个参数也是一条将在结果中显示的消息。

    运行测试后,您将得到以下结果:

    使用 QUnit 测试 JavaScript 代码:分步指南

    由于所有这些断言都已成功通过,我们可以非常确定 isEven() 将按预期工作。

    让我们看看如果断言失败会发生什么。

    // Let's test this functionfunction isEven(val) {return val % 2 === 0;}test('isEven()', function() {ok(isEven(0), 'Zero is an even number');ok(isEven(2), 'So is two');ok(isEven(-4), 'So is negative four');ok(!isEven(1), 'One is not an even number');ok(!isEven(-7), 'Neither does negative seven');// Failsok(isEven(3), 'Three is an even number');})

    登录后复制

    结果如下:

    使用 QUnit 测试 JavaScript 代码:分步指南

    断言失败是因为我们故意写错了,但在你自己的项目中,如果测试没有通过,并且所有断言都是正确的,你就知道发现了一个bug。

    更多断言

    ok() 并不是 QUnit 提供的唯一断言。在测试项目时,还有其他类型的断言很有用:

    比较断言

    比较断言 equals() 期望其第一个参数(即实际值)等于其第二个参数(即期望值)。它与 ok() 类似,但同时输出实际值和期望值,使调试更加容易。与 ok() 一样,它采用可选的第三个参数作为要显示的消息。

    所以代替:

    test('assertions', function() {ok( 1 == 1, 'one equals one');})

    登录后复制

    使用 QUnit 测试 JavaScript 代码:分步指南

    你应该写:

    test('assertions', function() {equals( 1, 1, 'one equals one');})

    登录后复制

    使用 QUnit 测试 JavaScript 代码:分步指南

    注意最后一个“1”,这是比较值。

    如果值不相等:

    test('assertions', function() {equals( 2, 1, 'one equals one');})

    登录后复制

    使用 QUnit 测试 JavaScript 代码:分步指南

    它提供了更多信息,使生活变得更加轻松。

    比较断言使用“==”来比较其参数,因此它不处理数组或对象比较:

    test('test', function() {equals( {}, {}, 'fails, these are different objects');equals( {a: 1}, {a: 1} , 'fails');equals( [], [], 'fails, there are different arrays');equals( [1], [1], 'fails');})

    登录后复制

    为了测试这种相等性,QUnit 提供了另一种断言:相同断言

    相同的断言

    相同的断言,same(),需要与 equals() 相同的参数,但它是一个深度递归比较断言,不仅适用于基本类型,还适用于数组和对象。在前面的示例中,如果将断言更改为相同的断言,它们将全部通过:

    test('test', function() {same( {}, {}, 'passes, objects have the same content');same( {a: 1}, {a: 1} , 'passes');same( [], [], 'passes, arrays have the same content');same( [1], [1], 'passes');})

    登录后复制

    请注意,same() 在可能的情况下使用“===”进行比较,因此在比较特殊值时它会派上用场:

    test('test', function() {equals( 0, false, 'true');same( 0, false, 'false');equals( null, undefined, 'true');same( null, undefined, 'false');})

    登录后复制

    构建你的断言

    将所有断言放在一个测试用例中是一个非常糟糕的主意,因为它很难维护,并且不会返回干净的结果。您应该做的是构建它们,将它们放入不同的测试用例中,每个测试用例都针对单一功能。

    您甚至可以通过调用模块函数将测试用例组织到不同的模块中:

    module('Module A');test('a test', function() {});test('an another test', function() {});module('Module B');test('a test', function() {});test('an another test', function() {});

    登录后复制

    使用 QUnit 测试 JavaScript 代码:分步指南

    异步测试

    在前面的示例中,所有断言都是同步调用的,这意味着它们依次运行。在现实世界中,还有很多异步函数,例如ajax调用或setTimeout()和setInterval()调用的函数。我们如何测试这些类型的功能? QUnit 提供了一种特殊的测试用例,称为“异步测试”,专门用于异步测试:

    我们先尝试用常规的方式来写:

    test('asynchronous test', function() {setTimeout(function() {ok(true);}, 100)})

    登录后复制

    使用 QUnit 测试 JavaScript 代码:分步指南

    看到了吗?就好像我们没有写任何断言一样。这是因为断言是异步运行的,当它被调用时,测试用例已经完成。

    这是正确的版本:

    test('asynchronous test', function() {// Pause the test firststop();setTimeout(function() {ok(true);// After the assertion has been called,// continue the teststart();}, 100)})

    登录后复制

    使用 QUnit 测试 JavaScript 代码:分步指南

    在这里,我们使用 stop() 暂停测试用例,调用断言后,我们使用 start() 继续。

    调用 test() 后立即调用 stop() 是很常见的;所以QUnit提供了一个快捷方式:asyncTest()。您可以像这样重写前面的示例:

    asyncTest('asynchronous test', function() {// The test is automatically pausedsetTimeout(function() {ok(true);// After the assertion has been called,// continue the teststart();}, 100)})

    登录后复制

    有一点需要注意:setTimeout() 将始终调用其回调函数,但如果它是自定义函数(例如 ajax 调用)怎么办?您如何确定回调函数将被调用?如果不调用回调,则不会调用 start(),整个单元测试将挂起:

    使用 QUnit 测试 JavaScript 代码:分步指南

    所以这就是你要做的:

    // A custom functionfunction ajax(successCallback) {$.ajax({url: 'server.php',success: successCallback});}test('asynchronous test', function() {// Pause the test, and fail it if start() isn't called after one secondstop(1000);ajax(function() {// ...asynchronous assertionsstart();})})

    登录后复制

    您将超时传递给 stop(),它告诉 QUnit,“如果在该超时后未调用 start(),则该测试应该失败。”您可以确信整个测试不会挂起,并且如果出现问题您将会收到通知。

    多个异步函数怎么样?你把start()放在哪里?你把它放在setTimeout()中:

    // A custom functionfunction ajax(successCallback) {$.ajax({url: 'server.php',success: successCallback});}test('asynchronous test', function() {// Pause the teststop();ajax(function() {// ...asynchronous assertions})ajax(function() {// ...asynchronous assertions})setTimeout(function() {start();}, 2000);})

    登录后复制

    超时应该足够长,以允许在测试继续之前调用两个回调。但是如果其中一个回调没有被调用怎么办?你怎么知道这一点?这就是expect() 发挥作用的地方:

    // A custom functionfunction ajax(successCallback) {$.ajax({url: 'server.php',success: successCallback});}test('asynchronous test', function() {// Pause the teststop();// Tell QUnit that you expect three assertions to runexpect(3);ajax(function() {ok(true);})ajax(function() {ok(true);ok(true);})setTimeout(function() {start();}, 2000);})

    登录后复制

    你向expect()传递一个数字来告诉QUnit你期望运行X个断言,如果其中一个断言没有被调用,数字将不匹配,并且你会被通知有事情发生错了。

    expect() 还有一个快捷方式:只需将数字作为第二个参数传递给 test() 或 asyncTest():

    // A custom functionfunction ajax(successCallback) {$.ajax({url: 'server.php',success: successCallback});}// Tell QUnit that you expect three assertion to runtest('asynchronous test', 3, function() {// Pause the teststop();ajax(function() {ok(true);})ajax(function() {ok(true);ok(true);})setTimeout(function() {start();}, 2000);})

    登录后复制

    结论

    这就是开始使用 QUnit 所需了解的全部内容。单元测试是在发布代码之前测试代码的好方法。如果您之前没有编写过任何单元测试,那么现在就开始吧!感谢您的阅读!

    在 Twitter 上关注我们,或订阅 Nettuts+ RSS Feed 以获取网络上最好的 Web 开发教程。

    以上就是使用 QUnit 测试 JavaScript 代码:分步指南的详细内容,更多请关注【创想鸟】其它相关文章!

    版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

    发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2692192.html

    (0)
    上一篇 2025年3月7日 17:37:59
    下一篇 2025年3月7日 17:38:09

    AD推荐 黄金广告位招租... 更多推荐

    相关推荐

    • 如何使用Linux进行文件系统性能调优

      如何使用linux进行文件系统性能调优 引言:文件系统是操作系统中非常关键的一部分,它负责管理和存储文件数据。在Linux系统中,有多种文件系统可供选择,如ext4、XFS、Btrfs等。为了获得更好的性能和效率,对文件系统进行调优是至关重…

      编程技术 2025年4月5日
      300
    • 超实用的 Linux 高级命令,程序员一定要懂!

      前言 在运维的坑里摸爬滚打好几年了,我还记得我刚开始的时候,我只会使用一些简单的命令,写脚本的时候,也是要多简单有多简单,所以有时候写出来的脚本又长又臭。 像一些高级点的命令,比如说 Xargs 命令、管道命令、自动应答命令等,如果当初我要…

      2025年4月5日 编程技术
      500
    • 如何使用Nginx进行HTTP请求的重定向和URL重写

      如何使用nginx进行http请求的重定向和url重写 Nginx是一个高性能的Web服务器和反向代理服务器,它也提供了强大的功能来管理HTTP请求的重定向和URL重写。在本文中,我们将介绍如何使用Nginx配置文件来实现这些功能,并提供代…

      编程技术 2025年4月5日
      200
    • 如何使用Linux进行网络性能调优

      如何使用linux进行网络性能调优 网络性能是计算机网络中一个非常重要的指标,它直接关系到用户的网络体验。在Linux系统中,我们可以通过一些简单的网络性能调优来提升网络的传输速度和稳定性。本文将介绍常见的Linux网络性能调优方法,并提供…

      编程技术 2025年4月5日
      200
    • 4 个 Linux 技巧,你值得拥有

      Linux 已经逐渐成为了最受开发者欢迎的操作系统。本文将介绍四个极为实用的技巧,相信这将能够提高您在 Linux 下的工作效率和流畅性,也让工作变得更为舒适、优雅。 1. 跳转目录优雅顺滑 1.1 bd 命令 快速回到 Bash 中的特定…

      2025年4月5日 编程技术
      200
    • 如何使用Nginx进行高性能的静态文件缓存

      如何使用nginx进行高性能的静态文件缓存 Nginx是一款轻量级的开源Web服务器,以其高性能和高并发能力而受到广泛的关注和使用。除了作为Web服务器之外,Nginx还有一个重要的功能,就是提供静态文件缓存功能,可以大幅优化网站的访问速度…

      编程技术 2025年4月5日
      200
    • 如何使用Linux进行进程调度优化

      如何使用linux进行进程调度优化 随着计算机技术的发展和互联网的普及,对计算机系统的性能要求越来越高。进程调度作为操作系统的重要功能之一,在提高系统性能方面起着重要作用。Linux作为一个开源的操作系统,具有良好的可定制性和扩展性,使得我…

      编程技术 2025年4月5日
      200
    • Linux 怎么防止 ssh 被暴力破解

      SSH 是一种广泛使用的协议,用于安全地访问 Linux 服务器。大多数用户使用默认设置的 SSH 连接来连接到远程服务器。但是,不安全的默认配置也会带来各种安全风险。 具有开放 SSH 访问权限的服务器的 root 帐户可能存在风险。尤其…

      2025年4月5日
      200
    • CentOS 7 系统优化脚本

      一、介绍 作为一名运维,经常会部署各种用途的操作系统,但在这些工作中,我们会发现很多工作其实是重复性的劳动,操作的内容也是大同小异,基于这类情况,我们可以把相同的操作做成统一执行的脚本,不同的东西作为变量手动输入。节约下来的时间不就可以做更…

      2025年4月5日
      200
    • 《恶魔城 多米尼斯合集》宣传片 现已推出

      《恶魔城 多米尼斯合集》公布最新宣传片,现已登陆switch。 https://www.bilibili.com/video/BV1ozs4etEir/ 以上就是《恶魔城 多米尼斯合集》宣传片 现已推出的详细内容,更多请关注【创想鸟】其它相…

      2025年4月5日
      200

    发表回复

    登录后才能评论