goldbergyoni /javascript-testing-best-practices

📗🌐 🚢 Comprehensive and exhaustive JavaScript & Node.js testing best practices (August 2025)

★ 24,610⑂ 2,079
JavaScriptCreated 2019-07-04testjavascript.com/
24,610
stars
+3+4+-1
2,079
forks
–
watchers
–
prs
–
issues
–
releases
–
discussions

README

👇 为什么本指南可以助你将测试能力提升到下一层级



 📗 45+ 最佳实践:非常全面彻底
这篇文章从 A 到 Z 给出了 JavaScript & Node.js 的稳定性指南。它为你整理总结了市面上大量的最佳博客文章、书籍以及工具。


 🚢 进阶:在基础上前进 10000 公里
从基础领域跨上前往进阶话题的旅程,包括:在生产环境测试、编译测试、基于属性的测试以及很多策略 & 专业工具。如果你仔细阅读了本指南中的每个字,则你的测试能力将有可能大大超过平均水平。


 🌐 全栈:前端、后端、CI、任何岗位
先了解通用的测试实践为其他应用层的打下基础。然后,在你自己的领域深入探索:前端/UI、后端、CI 甚至是他们所有的层面。



 作者 Yoni Goldberg
- 一位 JavaScript & Node.js 顾问
- 👨‍🏫 我的测试网站 - 在欧洲 & 美国了解 我的测试网站
- 在 Twitter 关注我
- 来 LA, Verona, Kharkiv, free webinar听我的演讲。后续工作待定。
- 我的 JavaScript 质量新闻 - 战略层面的视野和信息




 内容列表

 第 0 章:黄金法则

一条启发所有人的建议(特殊的 1 条)

 第一章:测试剖析

基础 - 搭建干净的测试(12 条)

 第二章:后端测试

高效地编写后端和微服务的测试(8 条)

 第三章:前端测试

为 UI(包括组件和 E2E 测试)编写测试(11 条)

 第四章:度量测试效果

度量测试质量(4 条)

 第五章:持续集成(CI)

JS 领域的 CI 指南(9 条)




 第 0 章:黄金法则



 ⚪️ 0 黄金法则:设计瘦测试

:white_check_mark: 建议: 测试代码与生产代码不同,要使它变得极其简单、短小、没有抽象、扁平化、使人愉悦、瘦。一段测试代码需要做到让人一眼就能看出其目的。

我们的思维空间被主体生产代码充满,因此无法腾出额外的“大脑空间”存放复杂的东西。如果向可怜的大脑中塞进其他复杂代码,将会使得整个部分变慢,而这个部分正是用来解决我们需要测试的问题的。这也是大部分团队放弃测试的原因。

另一方面,测试是一个友好的助手,一个你乐于与之合作、投资小回汇报大的助手。科学证明我们有两套大脑系统:系统 1 用于无需努力的活动如在一个空旷的路上开车;系统 2 用于复杂和繁琐的工作如算一道数学表达式。将你的测试为系统 1 设计,当你看一段测试代码时,需要像改 HTML 文档一样简单而不是像计算 2 × (17 × 24)。

为了达到这个目的,我们可以通过选择性价比高、投入产出比(ROI)高的技术、工具以及测试对象。仅测试需要的内容,努力保持其灵活性,某些时候甚至值得去舍弃一些测试来换取灵活性和简洁性。

!alt text

下面的大部分建议衍生自这一原则。

 准备好开始了吗?




 第一章: 测试剖析



 ⚪ ️ 1.1 每个测试用例的名称必须包含三个部分

:white_check_mark: 建议: 一个测试报告需要让不熟悉代码的人(测试、运维)明确知道新的变更是符合需求。因此测试名称需要从需求层面描述,并且包含三个部分:

(1) 被测的是什么?(比如 ProductsService.addNewProduct 方法)

(2) 在什么条件和场景下?(比如没有 向该方法传入 price 参数)

(3) 期望的结果是什么?(比如不允许添加该产品)




❌ 否则: 当一个名为“新增产品”的测试用例挂掉之后,你如何准确找到是哪里出问题了?



👇 Note: 每一条后面会有一个 代码示例,有时候还会放一张图片说明。

✏ 代码示例



 :clap: 正例: 一个包含三部分的用例名

!

javascript
//1. unit under test
describe('Products Service', function() {
  describe('Add new product', function() {
    //2. scenario and 3. expectation
    it('When no price is specified, then the product status is pending approval', ()= {
      const newProduct = new ProductService().add(...);
      expect(newProduct.status).to.equal('pendingApproval');
    });
  });
});




 :clap: 正例: 一个包含三部分的用例名
!alt text





 ⚪ ️ 1.2 使用 AAA 模式构造测试内容

:white_check_mark: 建议: 将你的测试内容划分为三个部分:布置,执行,断言 —— Arrange, Act & Assert (AAA)。这样读者就无需动用脑细胞理解你的测试内容了:

1st A - 准备(Arrange):一些用于提供上下文的代码。可能包含:构造数据、添加 DB 记录、mocking/stubbing 对象,以及其他的准备代码;

2nd A - 执行(Act):执行测试单元。通常一行代码。

3rd A - 断言(Assert):保证得到的值符合预期。通常一行代码。





❌ 否则: 你不仅要花大量时间理解这段代码,而且本该是最简单的部分却耗费了你的大量脑细胞。



✏ 代码示例



 :clap: 正例: 一个使用 AAA 模式构造的测试用例

! !

javascript
describe('Customer classifier', () = {
    test('When customer spent more than 500$, should be classified as premium', () = {
        //Arrange
        const customerToClassify = {spent:505, joined: new Date(), id:1}
        const DBStub = sinon.stub(dataAccess, "getCustomer")
            .reply({id:1, classification: 'regular'});

        //Act
        const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);

        //Assert
        expect(receivedClassification).toMatch('premium');
    });
});




 :thumbsdown: 反例: 没有分隔、一大坨、难以解释

j

Snapshot: 2026-11-10T09:35:25Z · Data license Apache-2.0 · JSON