自您启动用户组列表和信息(UGLI)应用程序以来,已经走了很长一段路。 您正在将本地数据存储在应用程序中,并通过RESTful Web服务提取远程数据。 该应用程序具有可移动的响应式Web设计 ,并且对其进行了语义标记,以充分利用搜索引擎优化(SEO)。 对于身份验证 ,用户可以创建本地专用帐户,也可以(通过OAuth)重用存储在其他位置的现有帐户。
但是,如果没有可靠的测试套件作为您的安全网,将UGLI应用程序投入生产时您会感到不舒服吗? 当然不是。 那在专业上是不负责任的。 我同意Neal Ford(作者兼国际发言人)的观点,他称测试为“软件开发的工程严谨性”。 每当我开始与新客户互动时,我都会先关注他们的测试套件,甚至是他们的设计文档。 测试的质量,数量和全面性与软件开发过程的成熟度有着直接的关系。 健康,积极维护的测试套件是项目整体健康的关键。 同样,任何将可测试性放在首位的框架都移到了我的清单顶部。 AngularJS是由测试人员编写的,我很难想到另一个易于测试的现代Web框架。 MEAN.JS堆栈扩展了现成的可测试性,包括对服务器端逻辑的测试。
“ AngularJS是由测试人员编写的,我很难想到另一个易于测试的现代Web框架。 ”
在本系列的开始,我向您介绍了MEAN堆栈的基本构建模块— 松散地连接在一起的小块组成了应用程序的生产组件。 现在是时候对各种框架和库执行相同的操作了,这些框架和库将用于测试您的应用并使之准备就绪。 我将向您介绍Karma :可插拔的测试运行程序,它使在任何测试框架中编写的测试在任意数量的真实Web浏览器(包括智能手机,平板电脑和智能电视)上运行并返回各种结果的过程变得微不足道。格式。 在此过程中,您将使用Jasmine进行客户端测试,使用Mocha进行服务器端测试,并使用伊斯坦布尔进行代码覆盖。
运行测试
因为您一直在使用MEAN.JS框架附带的Yeoman生成器,所以您已经准备好了几个生成的测试。 输入grunt test
来运行它们。 您应该看到与清单1相似的结果。
清单1.运行生成的测试
$ grunt test
Running "env:test" (env) task
Running "mochaTest:src" (mochaTest) task
Application loaded using the "test" environment configuration
Running "karma:unit" (karma) task
INFO [karma]: Karma v0.12.31 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Mac OS X)]: Connected on socket 6zkU-H6qx_m2J6lY4zJ8 with id 51669923
PhantomJS 1.9.8 (Mac OS X): Executed 18 of 18 SUCCESS (0.016 secs / 0.093 secs)
Done, without errors.
如果有错误或警告,请不要担心; 测试将被支架化以匹配最初实现时的模型和控制器。 如果您一直在更改被测代码(CUT),而不更新相应的测试,则可能会遇到错误。
每当单元测试失败时,我都会很高兴。 单元测试是代码库的断路器。 在家里,您将断路器放在电网和昂贵的个人电子设备之间。 这样,当潜在的有害电涌通过电线进入时,您将损失一个35美分的断路器,而不是一台价值3500美元的笔记本电脑。 同样,每个破坏单元测试都是您看到的错误,而您的用户则看不到。
如果可以的话,请花点时间修复损坏的测试。 错误的常见来源是测试对删除或更改的字段名称的依赖。 服务器端测试在应用程序/测试中。 客户端测试存储在每个公共/模块的测试目录中。 如果您无法立即在测试中看到错误的根源,请不要删除测试; 只需将其暂时移出目录树即可。
现在您可以进行干净的测试运行了,是时候解构该过程了。
了解Grunt test
任务
当您键入grunt test
,希望您自己问:“嗯,我想知道Grunt如何运行这些测试。” 如您所知,Grunt运行您的构建脚本。 在文本编辑器中打开gruntfile.js,并一直滚动到文件底部。 您可以看到正在注册的test
任务:
// Test task.
grunt.registerTask('test', ['env:test', 'mochaTest', 'karma:unit']);
grunt.registerTask
的第一个参数是任务的名称,在本例中为test
。 下一个参数是一组相关任务。 test
任务首先设置特定于测试环境的值,然后运行用Mocha编写的所有服务器端测试,最后通过Karma启动客户端测试。
在gruntfile.js中向上滚动直到找到env
任务:
env: {
test: {
NODE_ENV: 'test'
}
},
此任务只需NODE_ENV
变量设置为test
。 回想一下,此变量可帮助Grunt确定哪些特定于环境的设置(在本例中为config / env / test.js)与config / env / all.js中的常用设置合并。
如果您在文本编辑器中查看config / env / test.js(如清单2所示),您将看到一个自定义的MongoDB连接字符串,以及各种OAuth提供程序的所有Passport设置的钩子:
清单2. config / env / test.js
'use strict';
module.exports = {
db: 'mongodb://localhost/test-test',
port: 3001,
app: {
title: 'Test - Test Environment'
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/facebook/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/google/callback'
},
// snip
};
本部分将是您将Passport指向Meetup身份验证策略的模拟实现的理想场所。 这样一来,您就不必依赖于在测试运行期间设置实际用户并向Meetup发出实际OAuth请求。
配置测试环境后,Grunt将运行用Mocha编写的所有服务器端测试。 这是mochaTest
任务:
mochaTest: {
src: watchFiles.mochaTests,
options: {
reporter: 'spec',
require: 'server.js'
}
},
旋钮和转盘
有关在进行Mocha测试时可以旋转的旋钮和转盘的更多信息,请参阅grunt-mocha-test
的插件文档 。
为什么用Mocha而不是Jasmine编写服务器端测试? Mocha的成熟度,可扩展性和插件使其成为我最喜欢的测试框架之一。 Mocha是测试Express路由,控制器和MongoDB交互之类的强大选择。 尽管Mocha可以轻松在Node.js和浏览器中运行测试,但是AngularJS团队更喜欢Jasmine进行浏览器内测试。 Jasmine针对客户端测试进行了更优化,因此MEAN.JS开发人员采用了最佳方法,并选择了一个强大的服务器端测试框架来测试服务器端,并选择了一个强大的客户端测试框架来测试客户端。客户端的事情。 您应该为选择的测试工具交换一个或两个框架而感到自在。
由于服务器端测试(按照定义)不在浏览器中运行,因此Karma不会启动Mocha测试。 茉莉花测试(Grunt test
依赖项的最后一部分)是由karma
任务触发的:
karma: {
unit: {
configFile: 'karma.conf.js'
}
}
在继续解构karma.conf.js文件之前,请在文本编辑器中打开package.json。 除了在dependencies
块中列出的运行时模块之外,您还可以在devDependencies
( 开发人员依赖项的缩写)块中看到几个构建时依赖项。 此块专门用于在键入npm install
时声明和安装与Mocha和Karma相关的Grunt插件:
"devDependencies": {
"grunt-env": "~0.4.1",
"grunt-mocha-test": "~0.10.0",
"grunt-karma": "~0.8.2",
"load-grunt-tasks": "~0.4.0",
// snip
}
业力介绍
我知道,业力是唯一获得硕士论文支持的考试选手。 Karma背后的想法更为简洁明了:该项目的任务说明:
事情应该很简单。 我们相信测试,因此我们希望使其尽可能简单。
而且很简单。 业力允许您在选择的框架中编写测试。 无论您是喜欢QUnit的测试驱动开发(TDD)样式还是Jasmine的行为驱动开发(BDD)样式,Karma都会很高兴地运行以任何样式编写的测试。 (如果您希望使用单个测试框架来编写服务器端和客户端测试,则Karma还为Mocha提供了一流的支持。)
经验丰富的Web开发人员知道在各种浏览器中测试其应用程序的重要性。 JavaScript的核心语言在所有浏览器中都非常一致,但是文档对象模型(DOM)的操纵和发出Ajax请求的方式远非标准化。 诸如jQuery和AngularJS之类的主流库在填充浏览器不兼容性方面做得很好,但是这不会使您陷入虚假的自满感。 一项测试值得一千种意见,并且证明您的应用程序可以在特定的浏览器中正常运行的证据要比简单地假设能胜任得多。
Karma提供了几个插件,可用于按需启动真正的浏览器,运行完整的测试套件,然后在完成后关闭浏览器。 该功能很方便在您选择的浏览器中本地运行测试,但是如果通过无头的连续集成服务器(例如Jenkins,Hudson或Strider)启动测试,则可能会受到限制。
幸运的是,您可以站起一台运行很长时间的Karma服务器,并捕获远程设备上的浏览器。 捕获浏览器就像在浏览器中访问Karma服务器的URL一样简单。 如果浏览器支持Web套接字( caniuse在每种主流的现代浏览器中都显示支持),则Karma服务器将与该设备保持长期,持久的连接。 随着新测试被添加到套件中,Karma服务器将通过有线将它们序列化到远程浏览器,运行它们并返回结果。
但是,如果无法量化结果,运行测试套件有什么好处? 业力为几个不同的记者提供插件。 报告程序可以很简单,就像在每次通过测试时在命令行上打印出一个点一样。 或者,报告程序可以生成完全格式化HTML,或者发出可以转换为您选择的输出的原始JUnit兼容XML。
测试框架,浏览器启动器和结果报告器均在karma.conf.js文件中定义。
了解karma.conf.js
在文本编辑器中打开karma.conf.js,如清单3所示。在该文件中,您会找到标记清晰的frameworks
, files
, reporters
browsers
和browsers
。
清单3. karma.conf.js
'use strict';
/**
* Module dependencies.
*/
var applicationConfiguration = require('./config/config');
// Karma configuration
module.exports = function(config) {
config.set({
// Frameworks to use
frameworks: ['jasmine'],
// List of files / patterns to load in the browser
files: applicationConfiguration.assets.lib.js.concat(applicationConfiguration.assets.js,
applicationConfiguration.assets.tests),
// Test results reporter to use
// Possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
//reporters: ['progress'],
reporters: ['progress'],
// Web server port
port: 9876,
// Enable / disable colors in the output (reporters and logs)
colors: true,
// Level of logging
// Possible values: config.LOG_DISABLE || config.LOG_ERROR ||
config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// Enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['PhantomJS'],
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// Continuous Integration mode
// If true, it capture browsers, run tests and exit
singleRun: true
});
};
返回参考package.json。 在该文件中,您可以在devDependencies
块中找到各种Karma插件的相应条目:
"devDependencies": {
// snip
"karma": "~0.12.0",
"karma-jasmine": "~0.2.1",
"karma-coverage": "~0.2.0",
"karma-chrome-launcher": "~0.1.2",
"karma-firefox-launcher": "~0.1.3",
"karma-phantomjs-launcher": "~0.1.2"
}
因为所有支架式客户端测试都是用Jasmine编写的,所以我建议将frameworks
数组保持原样。 但是,正如您将在本节的后面看到的那样,您可以随意添加和删除浏览器。
引入PhantomJS
如果您是一名Web开发人员,但对PhantomJS浏览器不熟悉,那么您将可以接受。 PhantomJS是Web测试人员最好的朋友之一。
容易被欺骗,将网络浏览器视为由熟悉的品牌名称标识的整体应用程序:Firefox,Chrome,Safari,Opera和Internet Explorer。 这些品牌名称只是描述特定技术集合(包括渲染引擎(用于HTML和CSS),脚本引擎(用于JavaScript)和插件子系统)的便捷方式。
“现在,您是一位经验丰富的MEAN开发人员,您已经非常熟悉将组件从浏览器中拔出并无头运行它们的过程。 运行无头渲染套件进行测试时,您应该感到宾至如归。 ”
一旦将浏览器识别为渲染工具包和脚本引擎的松散集合,就会打开全新的理解水平。 例如,在1990年代中期发布2.0版时,Netscape Navigator浏览器拥有90%以上的市场份额。 几年后,IE接管了该市场的领导地位。 但是,近年来,渲染工具包-WebKit-而不是浏览器占有多数市场份额。 这是因为直到最近(请参阅WebKit,见Blink侧栏),基于WebKit的Safari,Mobile Safari,Chrome,Android浏览器,BlackBerry浏览器,Kindle设备,PlayStation,三星智能电视,LG智能电视,松下智能电视等等。 尽管这些应用程序和设备都是由不同的公司和项目组装而成的,但它们共享一个通用的渲染工具包,用于显示HTML和使用CSS对其进行样式设置。
WebKit,见识眨眼
Google在2013年发布了一个新闻,宣布将分叉WebKit项目并创建一个名为Blink的单独的渲染工具包。 不久之后,Opera宣布将停止开发其自定义渲染工具包,而采用Blink。 (此列表显示了所有主要浏览器的基础渲染工具。)
苹果公司最初于2005年从KHTML渲染引擎派生WebKit,但现在继续积极开发和维护该项目。 (有关更多信息,请参见Wikipedia中的WebKit条目。)
那么,这与PhantomJS有什么关系? PhantomJS网站告诉我们:
PhantomJS是可使用JavaScript API编写脚本的无头WebKit。
无头服务不需要监视器或GUI。 这听起来很适合在无监视器的连续集成服务器上运行基于浏览器的单元测试,不是吗? ( SlimerJS项目提供了类似的功能:运行无头Gecko渲染工具包来测试Firefox浏览器中发生的页面渲染。)
现在,您已经是一位经验丰富的MEAN开发人员,您已经非常熟悉如何从浏览器中拔出组件并无头运行它们:Node.js是Google Chrome的无头脚本脚本引擎(V8)。 运行无头渲染套件进行测试时,您应该感到宾至如归。
回顾karma.conf.js,您可以看到PhantomJS在browsers
数组中。 现在,您了解了如何在没有看到GUI启动的情况下在Jasmine客户端测试中运行和通过所有浏览器。
配置业力以启动其他浏览器
业力为所有主要浏览器提供启动器。 如果您回头查看package.json的devDependencies
块,可以看到已经为Firefox和Chrome安装了启动器。 如果您在计算机上安装了这些浏览器,则将它们添加到karma.conf.js中的browsers
阵列,然后键入grunt test
以在新添加的浏览器中运行测试套件。
我鼓励您访问npm网站并搜索karma launcher
以查看所有受支持的浏览器的列表。 您安装每个启动器,然后通过键入npm install karma- xxx -launcher --save-dev
将其添加到package.json中。 安装启动程序后,将其添加到karma.conf.js中的browsers
数组中,然后重新运行测试。
捕获无法启动的浏览器
Karma启动器通常用于启动位于同一台计算机上的浏览器。 回想一下,Karma还可以用于在远程浏览器上运行测试-例如智能手机,平板电脑和智能电视。 Karma可以捕获任何支持Web套接字的浏览器,并将其用作测试目标。
要捕获远程浏览器,必须首先在测试运行之间使Karma服务器保持运行状态。 要使Karma服务器永久运行,请在singleRun
值更改为false
:
// Continuous Integration mode
// If true, it capture browsers, run tests and exit
singleRun: true
如果您重新启动Karma服务器或任何捕获的浏览器,它们将尝试重新连接并重新运行所有测试。
既然Karma服务器已经启动并正在运行,请在远程浏览器中通过URL http:// your.server.ip.address :9876访问它。 这就是使用Karma捕获无法启动的浏览器所需要的全部。
添加其他Karma记者
现在您可以轻松添加其他测试和浏览器,请考虑添加其他报告程序以捕获并显示测试结果。
首先,将dots
报告程序添加到karma.conf.js中的reporters
数组中。 下次输入grunt test
,您会看到一系列点在屏幕上飞舞-每个通过测试。
这些点很可爱,但短暂。 除非您看着屏幕正在运行,否则如何知道通过了多少测试? 也许安装一个更耐用的记者是有必要的。
karma-html-reporter
最有可能是您想要的。 如图1中的示例所示,您将获得每个测试的详细口头测试结果,格式为HTML。
图1. karma-html-reporter
生成karma-html-reporter
要安装karma-html-reporter
,请键入npm install karma-html-reporter --save-dev
。 然后对其进行配置,如下所示编辑karma.conf.js:
reporters: ['progress', 'html'],
htmlReporter: {
outputDir: 'karma_html'
},
有关完整的配置选项集,请参见karma-html-reporter
软件包详细信息 。
如果您更喜欢原始XML输出而不是精细HTML输出,请考虑安装karma-junit-reporter
。 要安装它,请键入npm install karma-junit-reporter --save-dev
。 然后如项目站点所示在karma.conf.js中对其进行配置。
您在npm网站上键入了karma launcher
,以搜索其他启动器。 您应该同样容易键入karma reporter
以查找其他业力报告程序。
显示Karma和伊斯坦布尔的代码覆盖率
没有显示测试代码覆盖范围,没有完整的测试基础架构。 以前的报告仅向您显示通过和失败的测试,而没有向您显示您忘记编写的测试。 一个好的代码覆盖率工具可以逐行向您显示单元测试已访问了代码库的哪些部分,更重要的是,单元测试尚未访问了哪些代码行。
如果通过键入npm install karma-coverage --save-dev
karma-coverage
插件(使用istanbul库),请输入npm install karma-coverage --save-dev
并根据说明进行配置,您将获得一组漂亮的报告,显示每行代码在您的应用程序中,如图2所示。
图2.覆盖率报告
绿线已被单元测试触及,红线是等待将来的单元测试的线。
模拟依赖
编写良好的单元测试的标志是它们的独立性。 他们绝不应该依赖实际的数据库或对实时Web服务进行实际的HTTP调用。 值得庆幸的是,模拟这些依赖关系是一种运行时间已久的测试方法。
可以考虑使用AngularJS附带的$httpBackend
模拟服务,而不是在客户端Jasmine测试中进行实际的Ajax调用。
可以考虑使用Mockgoose (它是Mongoose(和MongoDB)的纯内存内置替代品,专门用于测试目的),而不是依赖于实际的MongoDB数据库进行测试。
使用Protractor.js运行端到端测试
到目前为止,您一直在运行单元测试。 单元测试(顾名思义)是不依赖GUI的测试。 单元测试适用于代码库的非UI部分。
但是,如何测试典型用户在使用您的应用程序时将执行的所有键入和单击按钮呢? 要测试这种行为,可以安装Protractor.js。
量角器主页上有完整的说明和示例。 这是简短的版本:键入npm install protractor --save-dev
来安装库。 接下来,编写Jasmine测试,这些测试访问特定的URL并与页面上的特定组件进行交互。 清单4显示了项目首页上的Protractor测试示例。
清单4.量角器测试
describe('angularjs homepage todo list', function() {
it('should add a todo', function() {
browser.get('http://www.angularjs');
element(by.model('todoText')).sendKeys('write a protractor test');
element(by.css('[value="add"]')).click();
var todoList = element.all(by.repeater('todo in todos'));
expect(todoList.count()).toEqual(3);
expect(todoList.get(2).getText()).toEqual('write a protractor test');
});
});
您可能已经todoText
,该测试将访问AngularJS主页,找到todoText
元素,键入测试字符串,然后单击添加按钮。 然后,它将运行一系列断言以确保出现期望值。
结论
就像我之前说的和我经常说的那样,一个测试值得一千个意见。 但是厚脸皮的重新连接仅在您可以使用可靠的软件实践对其进行备份时才有效。 如果您将从本文中汲取的教训放到适当的位置,那么您将步入“工程严谨”的道路,这是快速发展,不断变化的软件生态系统的一部分。
翻译自: https://www.ibm/developerworks/opensource/library/wa-mean6/index.html
更多推荐
测试MEAN堆栈
发布评论