节点测试要点(节点开发人员的测试指南)

2025-06-07

节点测试要点(节点开发人员的测试指南)

最近,我开始为 Node 编写复杂的测试,并意识到需要使用多个库才能有效地测试 Node 项目。然而,我找不到关于如何结合使用这些库来创建健壮测试的全面指南,所以我决定分享我的经验,以节省大家的时间。
请注意,这不是一个循序渐进的教程,而是一个关于这些工具以及如何结合使用的指南。

工具箱

首先我来介绍一下我测试用到的工具。

  1. Mocha:用于测试 JS 的框架。基本上是测试的骨架。
  2. Chai:带有许多有用插件的断言库。
  3. Nock:一个允许您使用自己的响应覆盖精确 http 请求的响应的库。
  4. Sinon:用于存根和模拟函数和对象的库。

现在让我们更详细地了解每个工具。

1.摩卡

Mocha 是主要的测试框架。我们使用它来:

  1. 定义测试场景。(使用describe
  2. 定义每个场景中的测试用例。(使用
  3. 使用mocha命令运行测试。

例如,如果我们想要测试登录功能的正常和异常情况,测试的最小框架可能如下所示:

describe('Login functionality', () => {
  it('should return authentication token', () => {
     // Logic to test success case
  });

 it('should return an error', () => {
     // Logic to test failure case
  });
});
Enter fullscreen mode Exit fullscreen mode

在上面的代码片段中,我们有一个测试场景“登录功能”,其中包含两个测试用例(1 个成功,1 个失败)。每个用例都包含实际的测试逻辑(在我们的例子中,使用了 chai、sinon 和 nock)。

2.柴

Chai 提供了许多断言,例如,你可以使用assert来检查两个值是否相等:assert.equal(foo, 'bar');
你还可以使用插件扩展 Chai,例如,Chai HTTP是一个允许测试 http 请求的 Chai 插件。在我们的登录示例中使用它:

// server is an instance of the http server
describe('Login functionality', () => {
  it('should return authentication token', async () => {
    const credentials = {
         email: 'user@mail.com',
         password: 'password123',
    };

    // send request to /login on our server
    const res = await chai.use(server)
        .post('/login')
        .set('Content-Type', 'application/javascript')
        .send(credentials);
    // assert that the response is ok and that it has access_token
    assert.equal(res.statusCode, 200);
    assert.property(res.body, 'access_token');
  });

});
Enter fullscreen mode Exit fullscreen mode

3.诺克

假设我们要测试一个函数,但是该函数本身会向另一个服务发出 http 请求,因此让测试依赖于另一个服务的响应是否有效是没有意义的。实际上,在测试过程中发出请求根本没意义,因为这可能会以不必要的方式影响其他服务。这就是我们开发 Nock 的原因。Nock 允许您覆盖特定的 http 请求并指定其特定的响应。在测试过程中,每当发出指定的请求时,请求都不会被发送,但您会收到您指定的响应。

为了更好地理解 Nock 的直观原理,假设我们的登录函数会向另一个记录登录用户数量的服务发送一个包含用户邮箱地址的 http 请求。在这种情况下,我们不想发送该请求,否则每次运行测试时都会记录错误的数据,因为每次都会添加一个登录用户。代码如下所示:

// server is an instance of the http server
describe('Login functionality', () => {
  it('should return authentication token', async () => {
    const credentials = {
         email: 'user@mail.com',
         password: 'password123',
    };

    /** 
    * if a post request is sent to analytics.com/api/loggedIn with 
    * payload { email: 'user@mail.com' }, then don't send the request 
    * and respond with 200
    */
    nock('analytics.com', {
      reqheaders: {
        'content-type': 'application/json',
      },
     })
      .post('/api/loggedIn', {
          email: credentials.email,
        })
      .reply(200);
    /** 
    * when we call /login on our server with user email 'user@mail.com'
    * it will call analytics.com/api/loggedIn with payload { email: 'user@mail.com' }
    * which is the request nocked above
    */
    const res = await chai.use(server)
        .post('/login')
        .set('Content-Type', 'application/javascript')
        .send(credentials);

    assert.equal(res.statusCode, 200);
    assert.property(res.body, 'access_token');
  });

});
Enter fullscreen mode Exit fullscreen mode

值得一提的是,nock 匹配精确的请求,这使您可以测试您的函数是否发送了正确的 http 请求。

4. 西农

你知道 Nock 是如何模拟 http 请求的吗?Sinon 模拟的是函数。
如果你正在测试一个调用了另一个函数B 的函数A,那么你可能需要模拟函数B的行为,并阻止它被调用。例如,假设我们的登录函数调用了“User”类中的“authenticate”函数,并且我们知道该函数在测试中输入的凭证会失败。那么我们可以使用 Sinon 来 stub 这个函数,并强制它在测试过程中成功执行:

describe('Login functionality', () => {
  it('should return authentication token', async () => {
    const credentials = {
         email: 'user@mail.com',
         password: 'password123',
    };

    /** 
    * when function authenticate that exists in class User is called with
    * payload { email: 'user@mail.com', password: 'password123' }, then  
    * don't call the function and instead return { success: true }
    */
    let stub = sinon.stub(User, 'authenticate');
    stub.withArgs(credentials).returns({ success: true });

    nock('analytics.com', {
      reqheaders: {
        'content-type': 'application/json',
      },
     })
      .post('/api/loggedIn', {
          email: credentials.email,
        })
      .reply(200);

    const res = await chai.use(server)
        .post('/login')
        .set('Content-Type', 'application/javascript')
        .send(credentials);

    assert.equal(res.statusCode, 200);
    assert.property(res.body, 'access_token');
  });

});
Enter fullscreen mode Exit fullscreen mode

结论

在本文中,我尝试创建一个简明的指南,指导如何使用 Mocha、Chai、Nock 和 Sinon 来测试 Node 服务器。我使用了一个登录端点作为示例,但并未包含所有实现细节,因为我希望文章尽可能简短,并专注于这些工具的结合使用,而不是每个工具的使用方法。话虽如此,这 4 个工具的功能和用例远比本文提到的要丰富得多。您可以通过阅读文档来了解更多关于每个工具的信息。

最后,我希望本文能够为您节省一些时间和精力,并让您更轻松地开始测试您的项目。

请在gohary.io查看我的其他文章

文章来源:https://dev.to/ielgohary/node-testing-essentials-a-node-developer-s-guide-to-testing-m16
PREV
如何计算系统设计容量
NEXT
🚀 使用 Node.js React.js 构建和生成发票 PDF 基于 Node.js 的开源 ERP CRM React.js 基于 Node.js 的开源 ERP CRM React.js