当前位置:首页 > 技术 > 正文内容

使用 Jasmine 进行 JavaScript 单元测试

访客 技术 2026年8月30日 1

随着互联网的飞速发展,Web 开发面临着前所未有的挑战。前端 JavaScript 代码量不断增加,多人协作以及团队成员技能差异,都要求对代码质量进行有效控制。Jasmine 作为一款流行的 JavaScript 测试框架,应运而生,为前端开发团队提供了标准化的测试解决方案。

Jasmine 概述

Jasmine 是一个独立的 JavaScript 测试框架,不依赖于任何其他 JavaScript 库。它拥有简洁直观的语法,能够让你轻松编写测试用例。当前最新版本为 2.0.0。

在 Jasmine 中,一个典型的单元测试由全局函数 describe 包裹,其中包含多个 it 函数,每个 it 函数又包含一个或多个断言(expectation)。

以下是一个基本的 Jasmine 测试示例:


describe("一个测试套件", function() {
  it("包含一个期望的测试用例", function() {
    expect(true).toBe(true);
  });
});
    

获取 Jasmine

你可以从 Jasmine GitHub Releases 下载最新版本的压缩包。推荐下载 2.0.0 版本。

解压后,在 lib/jasmine-2.0.0 目录下,你会找到进行 JavaScript 测试所需的核心文件。

Jasmine 的运行依赖

Jasmine 的运行需要以下几个部分:

  1. 运行环境: 浏览器(如 IE, Firefox, Chrome)或 Node.js。
  2. 源文件: 由开发人员编写的业务逻辑 JavaScript 文件。
  3. 测试文件: 遵循 Jasmine API 编写的测试脚本。
  4. 结果输出: 测试结果会显示在网页或控制台中。

Jasmine 的使用

在你的项目中创建一个 test.html 文件,并包含以下基本结构:


<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <title>Jasmine JavaScript 单元测试框架</title>
    <link rel="stylesheet" href="jasmine/jasmine.css">
    <script src="jasmine/jasmine.js"></script>
    <script src="jasmine/jasmine-html.js"></script>
    <script src="jasmine/boot.js"></script>
</head>
<body>
    <p>JavaScript 单元测试示例</p>
    <script src="src.js"></script>
    <script src="test.js"></script>
</body>
</html>
    

在这个 HTML 文件中,我们引入了以下文件:

  • jasmine.js: Jasmine 框架的核心文件。
  • jasmine-html.js: 用于在网页上显示测试结果的文件。
  • boot.js: Jasmine 框架的启动脚本,应在 jasmine.js 加载完成后执行。
  • src.js: 包含你的业务逻辑代码。
  • test.js: 包含你的 Jasmine 测试用例。
  • jasmine.css: 用于样式化测试结果页面的 CSS 文件。

boot.js 文件通常包含以下内容,用于初始化 Jasmine 环境并执行测试:


// report.js
(function() {
    var jasmineEnv = jasmine.getEnv();
    jasmineEnv.updateInterval = 1000; // 更新间隔(毫秒)

    var htmlReporter = new jasmine.HtmlReporter();
    jasmineEnv.addReporter(htmlReporter);

    jasmineEnv.specFilter = function(spec) {
        return htmlReporter.specFilter(spec);
    };

    var originalWindowOnload = window.onload;

    window.onload = function() {
        if (originalWindowOnload) {
            originalWindowOnload();
        }
        runJasmineTests();
    };

    function runJasmineTests() {
        jasmineEnv.execute();
    }
})();
    

src.js 文件用于存放业务逻辑:


// src.js
function greet(name) {
    return "Hello " + name;
}
    

test.js 文件则编写对应的单元测试:


// test.js
describe("一组基本函数", function() {
    var personName;

    it("测试 greet 函数", function() {
        personName = "Alice";
        var expectedGreeting = "Hello Alice";
        expect(expectedGreeting).toEqual(greet(personName));
    });
});
    

打开 test.html 文件,你将在浏览器中看到测试结果。

测试先行 (Test-Driven Development - TDD)

测试先行是一种开发实践,即在编写实际功能代码之前,先编写测试用例。这有助于确保代码的质量和设计的合理性。

假设我们有一个需求:实现一个单词反转的功能(例如,"ABCD" -> "DCBA")。

首先,在 test.js 中添加对应的测试用例:


// test.js (追加)
it("测试反转单词功能", function() {
    expect("DCBA").toEqual(reverse("ABCD"));
});
    

此时运行测试,会因为 reverse 函数未定义而失败。

接着,在 src.js 中添加 reverse 函数的初步实现:


// src.js (追加)
function reverse(str) {
    return "DCBA"; // 这是一个临时的、不正确的实现
}
    

再次运行测试,测试将通过,但这并不意味着功能完全正确。我们需要增加更多样化的测试用例来验证。

修改 test.js,增加更多测试场景:


// test.js (修改)
it("测试反转单词功能", function() {
    expect("DCBA").toEqual(reverse("ABCD"));
    expect("ecoC").toEqual(reverse("Coce")); // 添加一个新测试
});
    

此时测试会再次失败,因为我们期望输入"Coce"时输出"ecoC",但当前函数返回"DCBA"。

修改 src.js 中的 reverse 函数,使其具备正确的逻辑:


// src.js (修改)
function reverse(str) {
    return str.split("").reverse().join("");
}
    

刷新浏览器,测试将再次成功。通过这种"测试先行"的方式,我们可以逐步构建健壮的代码。

Jasmine 语法实践

以下将介绍 Jasmine 的常用语法,这些都可以在 test.js 中进行实践。

断言 (Expectations)

Jasmine 提供了丰富的断言方法来验证代码的行为:


describe("Jasmine 函数套件", function() {
    describe("断言", function() {
        it("各种断言示例", function() {
            // 值相等
            expect("Hello").toEqual("Hello");

            // 匹配正则表达式
            expect("123.45").toMatch(/\d+\.\d{2}/);

            // 是否为 null
            expect(null).toBeNull();

            // 字符串是否包含子串
            expect("JavaScript").toContain("Script");

            // 数值比较
            expect(10).toBeLessThan(20);
            expect(50).toBeGreaterThan(30);

            // 变量定义和类型
            var enabled = true;
            var data;
            expect(enabled).toBe(true); // 严格相等
            expect(enabled).toBeDefined(); // 是否已定义
            expect(data).toBeUndefined(); // 是否未定义
            expect(enabled).toBeTruthy(); // 是否为真值
            expect(!enabled).toBeFalsy(); // 是否为假值

            // 检查函数是否抛出异常
            var safeFunction = function() { return 1 + 1; };
            var errorFunction = function() { throw new Error("Something went wrong"); };
            expect(safeFunction).not.toThrow();
            expect(errorFunction).toThrow();
        });
    });
});
    

设置与清理 (Setup and Teardown)

beforeEachafterEach 可以在每个 it 块执行前后运行指定代码,常用于初始化和清理测试环境。


    describe("设置与清理", function() {
        var counter;

        beforeEach(function() {
            // 在每个 it 块执行前运行
            counter = 0;
            counter++;
        });

        afterEach(function() {
            // 在每个 it 块执行后运行
            counter = 0;
        });

        it("第一个测试用例", function() {
            expect(counter).toEqual(1);
        });

        it("第二个测试用例", function() {
            expect(counter).toEqual(1);
            expect(true).toBe(true); // 可以包含多个断言
        });
    });
    

禁用测试套件

使用 xdescribe 可以临时禁用整个测试套件,使用 xit 可以禁用单个测试用例。这在调试或暂时跳过不相关测试时非常有用。


   xdescribe("禁用测试套件", function() { // 这个套件及其内部的测试将不会执行
        it("禁用中的测试", function() {
            expect("test").toBe("test");
        });
    });
    

异步测试

Jasmine 提供了 runs, waits, 和 waitsFor 来处理异步操作的测试。


   describe("异步支持", function() {
        var result, isComplete;
        
        it("异步操作测试", function() {
            runs(function() {
                isComplete = false;
                result = null;
                // 模拟一个异步操作,如 setTimeout
                setTimeout(function() {
                    isComplete = true;
                    result = "Async Data";
                }, 500);
            });

            // 等待 isComplete 变为 true,或者超时
            waitsFor(function() {
                return isComplete;
            }, "异步操作应在 1 秒内完成", 1000); // 1000ms 超时

            runs(function() {
                expect(result).toBe("Async Data");
            });
        });
    });
    

Jasmine API 概览

  • describe(description, function)`: 定义一个测试套件。
  • it(expectation, function)`: 定义一个具体的测试用例。
  • beforeEach(function)`: 在套件内所有 it 执行前运行。
  • afterEach(function)`: 在套件内所有 it 执行后运行。
  • expect(actual)`: 开始一个断言。

常用匹配器 (Matchers)

  • toBe(expected)`: 严格相等比较 (===)。
  • toEqual(expected)`: 递归比较对象或数组的值。
  • toMatch(expected)`: 使用正则表达式进行字符串匹配。
  • toBeDefined()`: 检查值是否已定义。
  • toBeUndefined()`: 检查值是否未定义。
  • toBeNull()`: 检查值是否为 null
  • toBeTruthy()`: 检查值是否为真值。
  • toBeFalsy()`: 检查值是否为假值。
  • toContain(expected)`: 检查数组或字符串是否包含某个元素/子串。
  • toBeLessThan(expected)`: 数值比较,小于。
  • toBeGreaterThan(expected)`: 数值比较,大于。
  • toBeCloseTo(expected, precision)`: 数值比较,在指定精度下近似相等。
  • toThrow(expected)`: 检查函数是否会抛出异常。

Jasmine 还提供了强大的 spy 功能,用于监控函数的调用情况。由于篇幅限制,此处不再详述,感兴趣的读者可以查阅 Jasmine 官方文档

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。