2016 年 1 月

第 31 卷,第 1 期

此文章由机器翻译。

工作的程序员如何成为平均: 以 MEAN 方式测试

通过 Ted Neward |2016 年 1 月

Ted NewardHowdy,"Nodeists。" 欢迎继续收听连续的输入、 输出、 数据库、 用户、 Ui、 Api 和平行宇宙 saga。(请参阅本系列中的第一部分 [msdn.com/magazine/mt185576] 如果错过了该引用。)

在上一篇文章 (msdn.com/magazine/mt595757),该应用程序到 API 终结点正在生成 (超级简化"persons"数据库) 其中出其 CRUD 功能包括 CUD,其中的上一期中有提供只是"R."舍入的点大小已达到 构建小幅度非常重要,当然,但还是值得拥有可以看到对其更改,并且反映询问关于它们时再对它们的内容。

这将启动一个令人不舒服的点。时构建这样一个 Web API,"简单测试"中的一名开发人员可以只是启动 Web 页并细查它来确定的内容是否工作正常,不是一个选项。嗯,当然,如上次指出,使用工具,如 cURL,Postman 或 Runscope 有助于更加轻松地细查它,但坦白地讲,信任眼球真正的重点不是。应用程序需要某些自动的测试,以帮助确保一切都平稳地正常运行。它应该是很容易运行,也包括代码,并且具有众多其他人已经记录不是我可以更好的所有其他特性的测试套件。

之前我下移到太深此路径中,但一个注释。也是争论"单位"测试中,有的代码的内部工作原理的高深知识并且 (通常) 需要某种级别的模拟周围有一点 (在这种情况下,快速请求和响应对象,例如)。这些应该很小,专注和执行速度快,因此它们可以作为 (之后立即编译,编译 C# 等语言) 的生成过程的一部分使用,而无需减的前提下程序员和猛从自己的想法排列它们。另一个视图是"集成"或"功能"测试,所更"external"的测试,这意味着测试依靠的框架来执行其操作并且层视为更加不透明实体。对于 Web Api,我倾向于使用后者;我发现,尝试编写单元测试通过速成版控制器往往会比权益来获取所有模拟权限的更多工作。假定控制器通常不应该易用且用途单一,不管怎样,并且有几个,如果有的话,我测试我自己的代码会影响 Express 层中发现的 bug,我发现外部测试要爆炸-为-您的 buck 讨论中更高的价值。

与该开,就可以编写一些测试的执行人员到目前为止我构建的 API。为此,有两个立即会想到的 Node.js 包: mocha 和 supertest。

获取测试

当然,与 Nodeish 的一切,生命开头 npm;在这种情况下,mocha 和 supertest 将需要添加到通过 npm 安装项目:

npm install --save-dev mocha supertest

(传统要单独执行每个操作时,没有理由执行的操作它们收集类似的特别是在这种情况下,我已经知道我想要同时使用这两者。)

除此之外,我将传递之前,请注意--保存开发人员参数: 这将 package.json 文件,这意味着它们是仅用于开发的依赖关系,并且,因此,当云的 devDependencies 节到两个宿主 (如 Microsoft Azure 中,例如) 准备在生产中执行代码,他们把它们留给。

Node.js 社区非常相似的项目的其余部分一样将其测试框架: 与小位,查找要组合在一起以开发人员定义方式,创建一个整体,即有可能令人赏心悦目向开发人员。在此情况下,开始使用 mocha 包,这是设计使"异步测试简单且充满乐趣"的测试包,测试根据其网站。它将用作基本"基架,"如果您愿意测试工作。但由于待测试的内容将 Web Api (并且我不想要编写此低级别的所有 HTTP 代码),第二个库、 supertest,将添加一些有用的 HTTP 特定测试行为。没有到集,一个更多的可选部分应库,我选择添加,因为我更喜欢行为驱动开发 (BDD) 的样式应断言。但 assert 包,其中附带 mocha,也存在对于那些喜欢传统 assert 样式。

一旦安装这两个包,测试开始时,无需诧异,通过编写第一个测试。尽管不是必需很常见的 Node.js 项目以创建一个单独的子目录的测试代码生活,调用,无需诧异,测试。在此目录中所示将第一个测试文件,getTest.js, 图 1

图 1 设置一些基准测试专为乐趣

var supertest = require('supertest');
  var express = require('express');
  var assert = require('assert');
  var should = require('should');
  describe('Baseline tests', function() {
    describe('#indexOf()', function () {
      it('should return -1 when the value is not present', function () {
        assert.equal(-1, [1,2,3].indexOf(5));
        assert.equal(-1, [1,2,3].indexOf(0));
        [1,2,3].indexOf(5).should.equal(-1);
        [1,2,3].indexOf(0).should.equal(-1);
      });
    });
  });

有几个事项需要在我开始前进行一些说明。描述方法是简单的输出执行对 — 字符串是应在测试控制台 (通常为命令提示符或终端窗口) 中显示的消息,该函数是应作为测试运行什么。请注意,描述块可以嵌套 — 特别是因为可以使用跳过函数来关闭整个块的必要进行此可以用于帮助拆分沿逻辑行的测试。It 函数然后介绍单一测试 — 这种情况下,若要测试,并再次应该充当 JavaScript 数组 indexOf 方法,该字符串传递到"it"是打印到测试控制台测试的说明。

嵌套的函数内部 it 调用是,无需诧异,实际测试,并且我在此处选择显示的断言,以及更类似于 BDD 应样式断言,传统的 assert 样式更 fluent API。坦白地讲,还有其他选项 (mocha Web 页列出了包含两个以上除了这些两个),但因为我想应该这是我要使用。但是,应该包将需要您可以通过 npm,安装而断言已使用 mocha 和 supertest 赶上了出来。

为了进行快速测试,只需类型"mocha"到目录中包含 app.js 和它将选取测试子目录中的测试自动。Node.js 却是要有一套为了便于执行; npm 命令行参数的 package.json 文件中的脚本集合中填入一个稍好约定然后,服务器上,可以启动"npm 开始"和"npm test"可以运行的测试不带管理员 (或云系统) 无需知道什么用于生成代码。这只需相应地填充的"脚本"集合内 package.json:

{
  "name": "MSDN-MEAN",
  "version": "0.0.1",
  "description": "Testing out building a MEAN app from scratch",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "test": "mocha"
  },
  // ...
}

现在,快速"npm test"将启动测试并找出,是,indexOf 可正常工作。

完成后,,让我们将关闭这些测试。(显然,您可以将它们全部删除,但我喜欢的内容与我的安装失败的情况下确定我知道工作原理,基线。) 是轻松地通过使用跳过一部分的链接的描述,如此处所示:

describe.skip('Baseline tests', function() {
  describe('#indexOf()', function () {
    it('should return -1 when the value is not present', function () {
      assert.equal(-1, [1,2,3].indexOf(5));
      assert.equal(-1, [1,2,3].indexOf(0));
      [1,2,3].indexOf(5).should.equal(-1);
      [1,2,3].indexOf(0).should.equal(-1);
    });
  });
});

这将现在跳过这些测试 — 它们仍列出到测试控制台中,但没有以指示运行这些测试旁边没有复选标记。

测试 Api

这确实很有趣,但已经很好地测试 indexOf;GET /persons 终结点...不尚未。

这是其中 supertest 发挥作用;使用它,可以创建知道如何查询终结点 (在此例中使用的服务器设置的"localhost"和端口 3000,如建立在此之前编写的应用程序代码),并验证其结果的小型 HTTP 代理。这意味着有几个事项需要添加;首先,应用程序代码作为测试的一部分进行加载和运行并且初始屏幕,可通过要求 app.js 文件中从该测试的第一行的父目录中:

require("../app.js")

这会启动 (这是非常方便的发现如果调试环境变量设置为应用程序,请记住) 该应用程序和运行。

然后,使用 supertest 库来创建一个请求对象,对本地主机服务器和端口 3000,您可以使用,以对发出一个请求 /persons 终结点与人 ID 为 1 (使其/人员/1,请记住),并验证它处于返回确定 (状态代码 200),返回的 JSON 和 JSON 正文包含预期内容如中所示 图 2

图 2 让我打开所有人!

var request = supertest("http://localhost:3000");
describe('/person tests', function() {
  it('should return Ted for id 1', function(done) {
    request
      .get('/persons/1')
      .expect(200)
      .expect('Content-Type', /json/)
      .expect(function(res) {
        res.body.id.should.equal(1)
        res.body.firstName.should.equal("Ted")
        res.body.lastName.should.equal("Neward")
        res.body.status.should.equal("MEANing")
      })
      .end(done);
    });
});

请注意如何请求对象有以便 get('/persons/1') 将针对该 URL 的 GET 请求转换为其自身的、 使用类似于速成版,谓词方法样式的 fluent API。后续预期方法,但是,执行完全什么这听起来像操作: 他们还期望特定类型的结果,,如果这不是这种情况,则整个测试失败。但是,最后一个结束方法务必要注意它,所以使用一个参数传递到"it":"已完成"的对象,它是一个不透明的回调,用于通知测试完成。因为 supertest 完成了所有这些测试按顺序,但以异步方式 (以 Node.js 方式),需要有一些发出信号将在测试完成 — 如果执行此操作没有使用,则在 (按每个测试) 的 2 秒之后, supertest 将假定已超时的测试并发出错误。

最后,因为空间逐渐短为此,让我们验证,您可以添加人员数据库通过使用 post 方法,并发送一个新的 JSON 对象,包含需要添加到系统,如中所示的 person 实例沿 图 3

图 3 验证,添加一个人实际的工作原理

it('should allow me to add a person', function(done) {
  request
    .post('/persons')
    .send({'firstName':'Ted', 'lastName':'Pattison','status':'SharePointing'})
    .expect(200)
    .expect('Content-Type',/json/)
    .expect(function(res) {
      should.exist(res.body.id);
      res.body.firstName.should.equal("Ted");
      res.body.lastName.should.equal("Pattison");
    })
    .end(done);
  })

很简单,是吧? 请注意,正文验证的第一行期望是测试 id 字段存在。但是,应该库不能信任不会是未定义,并调用方法或属性上的未定义生成异常,因此,您需要使用应直接以验证它是否存在。除此之外,不过,它会读取可以很好地。

两个其他方法的要求的测试,PUT 和 DELETE,是很容易编写。PUT 终结点测试将使用设置而不是 post,并且该 URL 将需要点到采用单数形式的人的 URL (/ 人员/1 的人员"嵌套""Neward"示例中)。要发送的 JSON 正文将外观相同的 POST 情况下,具有不同值 (因为测试是若要查看这些更新将会接受),并随后测试返回的 JSON 正文,(因为测试也是以查看是否这些更新将会反映在返回的新对象) 将反映这些更新。并删除终结点测试将使用 delete 方法,并在 URL 中传递了某个特定人员 (/ 人员/1),并且这一次,在既没有 JSON 正文中传递也需要获得返回。(尽管它看起来以返回已删除的对象从删除的终结点的通用 API 约定,但老实说,我个人永远不会真正看过太大意义,而且以前从未使用返回的 JSON 正文出于任何原因。)

与五个测试中的位置,并会借助在 package.json 中的最新改进的 npm 脚本标记,保持只是为了运行 npm 测试,请通过观看 rest 运行程序执行它的任务、 看到錯誤、 执行源代码提交-和-push,和使用新代码更新 Azure 环境。

总结

也有一些有关 mocha 材料 supertest 应该和我没有空间来深入 — 例如,如大多数测试框架,咖啡支持之前和之后将运行每个测试; 周围的挂钩此外,supertest 库支持使用基于 cookie 的请求,这与使用 cookie 来维护某种类型的会话状态的 HTTP 端点一起使用时非常有用。幸运的是,围绕着这些库的文档就很不错,和数量众多示例 Web 说说而已。唉,现在,就可以回想一下,说 … 祝您编码愉快!


Ted Neward是 Neward & associates 的负责人,基于西雅图的 polytechnology 咨询公司在主体。他曾写过 100 多篇文章,是 F # MVP 和十几本书对他的名字。如果您有兴趣请他参与您的团队工作,请通过 ted@tedneward.com 与他联系,或通过 blogs.tedneward.com 访问其博客。

感谢以下技术专家对本文的审阅: Shawn Wildermuth