写点什么

Poang,基于 Node.js 的自动化测试范例

2012 年 6 月 04 日

Poang 是一个基于 express framework 部署在 Heroku / MongoLab 上的 Node.js 应用,该应用的作者 Stephen Bronstein 详细描述了如何写单元测试、功能测试、集成测试并在云端使用 Strider 做持续集成开发。

Poang 主要业务逻辑是使用 Everyauth 做本地身份认证,并将用户身份信息通过 Mongoose-Auth 持久化到 MongoDB 中去 ( Mongoose 做对象建模),利用 Connect-Mongo 做会话保存。 Poang 中的认证代码 auth.js 大部分取自 Mongoose-Auth docs

测试代码使用了多种技术框架, Mocha 做单元测试, should 做断言, Sinon.JS 监测以及制造 mock 数据, Zombie.js 做基于浏览器的轻量级集成测试。

单元测试

写一个基于 web/ 数据库的单元测试比较麻烦,有很多配置项需要添加,这里举一个简单例子来阐述如何使用 Mocha 框架做单元测试

describe(‘index’, function() {
describe(’#timesTwo()’, function() {
it(‘should multiply by two’, function() {
var x = 5;
var xTimesTwo = index.timesTwo(x);
xTimesTwo.should.equal(10);
});
});
});

注:前三行表述了单元测试的目标类和目标函数 (一个乘二函数),单元测试的代码体输入参数为 5,利用 should 断言来校验返回值是否为 10

功能测试

1) Case1

创建 mock 请求对象 mock_req,来验证服务端的身份认证功能。使用 Sinon.JS 的 spy 功能监测 mock 响应对象 mock_res 是否有做重定向,如果没有做重定向,则将 mock 响应对象的 http 状态码设置为 200

var mock_req = {session: {}};
var mock_res = {redirect: function() {}, end: function() {}};
sinon.spy(mock_res,“redirect”);
middleware.require_auth_browser(mock_req, mock_res, function() {
mock_res.statusCode = 200;
});

服务端会验证 mock 请求对象是否包含用户信息,因为我们 mock 请求不包含用户对象,所以服务端会返回 http 401 状态码 (未授权),并跳转到 login 页面

mock_res.statusCode.should.eql(401);
mock_res.redirect.getCall(0).args[0].should.equal(’/login’);

2) Case2

重新创建一个 mock 对象,包含用户信息,此时我们断定,mock 响应对象的状态码被设置为 200

mock_req = {user: {}};
middleware.require_auth_browser(mock_req, mock_res, function() {
mock_res.statusCode = 200;
});
mock_res.statusCode.should.eql(200);

集成测试

接下来使用 Zombie.js 做轻量级基于浏览器的集成测试,步骤如下:

首先启动 Poang 应用实例,随机选择一个服务端口号 (当然也可以自己指定一个端口号,但要保证该端口号没有被占用)

var TEST_PORT = Math.floor(Math.random()*61439 + 4096);
before(function() {
var server = app.init(config);
// should check to see if something is listening on the port first
server.listen(TEST_PORT);
console.log(‘Server is listening on port %s’, TEST_PORT);
});

确认下这个服务是可用的,并且页面的标题是”Poang”

var browser = new zombie();
browser.visit(base_url, function () {
browser.success.should.be.ok;
if (browser.error) {
console.dir(‘errors reported:’, browser.errors);
}
done();
});
browser.text(“title”).should.eql(“Poang”);

注册一个用户,校验注册流程是否成功

var browser = new zombie();
browser.visit(base_url + “register”, function () {
browser.query("#register").should.be.ok;
// Fill email, password and submit form
browser.fill(“email”, test_email).fill(“password”, “secret”).
pressButton(“register”, function() {
// Form submitted, new page loaded.
browser.success.should.be.ok;
browser.location.pathname.should.eql("/");
done();
});
});

因为每次集成测试,都会注册同样的帐号,为了避免困扰,我们在跑完集成测试的时候可以将帐号从数据库中删掉 (这个取决于测试的具体策略,可以灵活调整)

after(function(done) {
var db_uri = process.env.MONGOLAB_URI || process.env.MONGODB_URI || config.default_db_uri;
mongoose.connect(db_uri);
// drop database
mongoose.connection.db.executeDbCommand( {dropDatabase:1}, function() {
console.log(“Dropped test database”);
done();
});
})

Strider 持续集成

Strider 是一个基于 Node.js Python 的持续集成平台, Strider 本身可以集成任意的测试框架,唯一的要求是应用必须支持”NPM Test”命令,而 Strider 对测试用具 TAP 有很好的集成性,所以 Poang 应用的描述文件 Package.json 会添加如下命令:

“test”: “mocha -R tap --globals o,section,data,m,k,i”

“–globals o,section,data,m,k,I”指定全局变量,不然会报全局变量遗漏错误

Strider 还在内测阶段,读者可以申请邀请码试用

以下是开发部署应用过程中,总结的最佳实践

MongoDB 的配置

启动 MongDB 的时候,需要关闭数据库文件大小的预分配,不然会间或出现单元测试连接数据库超时

mongod --noprealloc --nojournal

Heroku/MongoLab 上部署 Poang 应用

  • 创建进程文件 Procfile,并指定如何启动该进程,详细可以参照 Heroku 指南
    • web: node app.js
  • MongoLab 数据库连接的环境变量
    • Poang 首先会使用 Heroku 提供的环境变量 process.env.MONGOLAB_URI,如果找不到则会使用 Strider 提供的 process.env.MONGODB_URI,如果还是找不到会使用本地系统默认配置 config.default_db_uri
  • Heroku 上添加 MongoLab 模块插件,使用 Heroku Toolbelt 创建 MongoLab 模块,命令如下 (如果在本地目录,无需指定应用名称)

heroku addons:add mongolab:starter --app [your_app_name]

感兴趣的读者,具体可以在 Github 参照 Poang 项目源代码以及 Stephen Bronstein 技术博客

2012 年 6 月 04 日 02:274333

评论

发布
暂无评论
发现更多内容

干货:不同场景容器内获取客户端源IP的方法

华为云开发者社区

容器 服务端 场景

anyRTC推流小助手-客户端推流(PUSH RTMP)工具

anyRTC开发者

技术 音视频 WebRTC 直播 RTC

居然有人仅凭这份《Java面试宝典》就成功拿到了阿里、京东、字节跳动等大厂offer

Java成神之路

Java 编程 程序员 面试

epoll的原理和流程

Dnnn

GO语言 MD5 四种实现方式

Dnnn

go

TCP三次握手和四次挥手

Dnnn

教师节送什么老师最开心?程序员三招解决家长送礼难题!

华为云开发者社区

编程 程序

实战解析丨如何对Mysql连接请求的tcpdump内容进行分析

华为云开发者社区

TCP/IP 数据传输

GO 语言交叉编译

Dnnn

go

起飞!这份技术点拉满的ELk+Lucene笔记,可能价值百万

小Q

Java lucene elasticsearch 架构 面试

阿里架构师耗时三个月整理的Spring实战笔记:入门到实战

Java架构师迁哥

【API进阶之路】用API打造一条自动化内容生产流水线

华为云开发者社区

自动化 API 部署

GO 语言超时实现

Dnnn

go

聊聊开发工程师如何转型产品经理

长沙造纸农

程序员 开发者 产品经理 转型 中年危机

bit比特, Byte字节,基础知识

Dnnn

初识大数据

yuanhang

大数据

Hadoop 简介

yuanhang

hadoop

Redis哨兵(sentinel )机制讲解

Dnnn

URL 去重的 6 种方案!(附详细实现代码)

王磊

Java

如何设计Upload组件思考

赵孔磊

程序员快乐器之JAVA代码生成工具

Learun

敏捷开发 快速开发 生成代码

学完微软技术总监整理的44 个微服务架构设计模式,我涨薪了

Java架构师迁哥

MYSQL中时间类型底层存储,DATETIME ,TIMESTAMP,INT 如何选择?

Dnnn

马云:今天的区块链并没有被人们认识到价值!

CECBC区块链专委会

区块链 阿里巴巴 马云

理解大端字节和小端字节

Dnnn

Linux命令netstat详解

Dnnn

Centos 上配置大数据环境

yuanhang

大数据

分布式追踪系统原理看不懂,40张图带你亲手实践

小Q

Java 架构 面试 分布式 系统设计

或许是史上最好的AQS源码分析了,AQS基础一

InfoQ_d2212957090d

AQS

算法与数据中台实践之网约车平台

博文视点Broadview

大数据 数据中台 中台 算法 数据

遇到银河提现不了网站维护审核怎么办?

丛林里的余光

数据库 网站平台 提现

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

Poang,基于Node.js的自动化测试范例-InfoQ