如何在 angularjs 控制器中对控制器进行单元测试

使用 AngularJS 开发一个大规模的单页应用(SPA) - 推酷
使用 AngularJS 开发一个大规模的单页应用(SPA)
首先下载源代码
------------------------------------------分割线------------------------------------------
免费下载地址在
用户名与密码都是
具体下载目录在 /2014年资料/9月/9日/使用 AngularJS 开发一个大规模的单页应用(SPA)
下载方法见
------------------------------------------分割线------------------------------------------
(SPA)这样一个名字里面蕴含着什么呢? 如果你是经典的Seinfeld电视秀的粉丝,那么你一定知道Donna Chang这个名字。Jerry跟Donna见面,Donna其实不是华人,但是却因在谈论其对中国的固有印象比如在针灸上的兴趣,以及偶然的一次单词发音带上了点儿中文口音,她将自己末尾的名字缩成了Chang Donna 在电话上同George的母亲交谈,(通过引用孔子)给她提了些建议。当George向自己的父母介绍Donna是,George的母亲意识到Donna并不是华人,因此并没有接受Donna的建议.
单页面引用 (SPA), 被定义成一个目的在于提供一种接近桌面应用程序的流畅用户体验单web页面应用程序,或者说网站. 在一个SPA中, 所有必需的代码 – HTML, JavaScript, 以及 CSS – 都是在单页面加载的时候获取,或者相关的资源被动态的加载并按需添加到页面中, 这常常是在响应用户动作的时候发生的. 尽管现代的Web技术(比如那些在HTML5中引入的技术)提供了应用程序中各自独立的逻辑页面相互感知和导航的能力,页面却不会在过程中重新加载任何端点,或者将控制转到另外一个页面. 同单页面应用程序的交互常常设计到同位于后台的web服务器的动态交互.
那么拿这项技术同 ASP.NET 的母版页Master Pages相比呢? 诚然 ASP.NET 的母版页让你可以为自己应用程序里的页面创建一个一直的布局。一个单独的母版页就可以定义好你想要在整个应用程序中的所有页面(或者一组页面)上应用的外观和标准动作. 然后你就可以再来创建你想要展示的内容各自独立页面. 当用户发起对内容页面的请求时,它们会将来自母版页的布局和来自内容页面的内容混合到一起,产生输出.
当你深入研究SPA和ASP.NET母版页实现这两者之间的不同时,你就开始会意识到它们之间相同的地方多于不同的地方——那就是SPA可以看做是一个简单的装着内容页面的外壳页面,就像是一个母版页, 只是SPA中的外壳页面不能像母版页那样根据每一个新的页面请求来重新装载和执行.
也许“单页面应用”是个不幸运的名字(像唐娜`程一样),让你相信这个技术不适合开发需要拓展到企业级,可能 包含上百页面以及数千用户的Web应用。
本文的目标是基于单页面应用程序开发出拥有数百页的内容,包括认证,授权,会话状态等功能,可以支持上千个用户的企业级应用。
希望你喜欢,并分享我的工作~ 带你走近AngularJS系列 :
带你走近AngularJS - 基本功能介绍
带你走近AngularJS - 体验指令实例
带你走近AngularJS - 创建自定义指令
如何在 AngularJS 中对控制器进行单元测试
在 AngularJS 应用中通过 JSON 文件来设置状态
AngularJS 之 Factory vs Service vs Provider
AngularJS —— 使用 ngResource、RESTful APIs 和 Spring MVC 框架提交数据
AngularJS - 概述
本文的样例包含的功能有创建/跟新用户账号,创建/更新客户和产品。而且,它还允许用户针对所有信息执行查询,创建和跟新销售订单。为了实现这些功能,该样例将会基于 AngularJS 来开发。&AngularJS 是一个由Google和AngularJS社区的开发人员维护的开源的Web应用框架。
AngularJS仅需HTML,CSS和JavaScript就可在客户端创建单页面应用。它的目标是是开发和测试更容易,增强MVC Web应用的性能。
这个库读取HTML中包含的其他定制的标签属性;然后服从这个定制的属性的指令,把页面的I/O结合到有标准JavaScript变量生成的模块中。这些JavaScript标准变量的值可以手动设置,或者从静态或动态的JSON数据源中获取。
更多详情见请继续阅读下一页的精彩内容 :
已发表评论数()
&&登&&&陆&&
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见Angularjs 中,在控制器中如何调用指令 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
已注册用户请 &
Sponsored by
100offer 程序员拍卖,让不缺工作机会的优秀程序员,安全匿名的在 2 天内收到 5-10 个优质面试机会,从而拥有一份激(shou)动(ru)人(geng)心(gao)的事业。
Promoted by
Angularjs 中,在控制器中如何调用指令
· 190 天前 · 854 次点击
大家好: 刚学Angularjs,现在遇到了一个问题。想请叫下大家:应用场景: 在app中我写了一个发送验证码的指令。然后在我的业务流程中,有个步骤是输入验证码的流程,所有我在那个页面调用了之前写好的指令。但是当用户输入验证码后,如果后端的接口返回的还是在发送验证吗的话,页面还是在此页面中。由于之前发送验证码有60s 的时间,所有用户点击按钮后,会发现什么都没有发生,感觉很奇怪。所有我想在指令中添加一个reset方法,让验证码重置下。但是我在我的controller 里面,注入指令。提示报错。应该是controller中无法注入directive 吧。所以。想请教下大家。我的这种需求在Angular中如何处里好?
& &190 天前
我把你文中的“所有”翻译成了“所以”,但还是不能完全看明白。“如果后端的接口返回的还是在发送验证吗的话,页面还是在此页面中。由于之前发送验证码有60s 的时间,所有用户点击按钮后,会发现什么都没有发生”这段话能描述得更具体些吗,还有报的什么错也贴一下。
& &190 天前
这儿有个较好的例子:重点看一下“内部动作”和“外部作用域交互”的内容。
& &190 天前
sorry。这样描述吧:用户进入页面A,页面A中有一个填写手机的文本框和一个发送验证码的按钮,还有提交按钮。当用户填写完手机号,点击发送验证码后,然后再点击提交按钮。提交按钮后ajax从后端去判断用户输入是否正确,在后端接口中有一个nextAction 参数。如果nextAction=2,则提示用户需要再次输入验证码。还是在呆页面A中。如果操作在60S之内的话,之前第一点击发送验证码按钮的文字会是“还剩下多少s”,这样对用户来说太突兀。所以我想到的解决方法是,在第一点击提交按钮,从后端拿到数据后,调用按钮指令的reset方法。但是尝试在controller里面注入指令,提示,不能使用注入的指令。
& &190 天前
虽然你文字写得很多,但看的人还是一头雾水, netxAction=2 和操作在60S之内是什么关系?什么叫“第一点击发送验证码”?你的需求用 angular 完全能实现,使用指令来实现思路也正确,但是,并不存在 controller 注入指令这回事儿,.controller 和 .directive 都是 module 的方法,controller 的作用是维持 $scope 对象,实现和 view 上的 ngModel 的双向绑定.你只需要正确的实现一个自定义指令就可以了。你所说的 reset 完全可以用指令内的方法去处理。
& &190 天前
真心抱歉!我文字表达不清楚。Angular初学者,谢谢你的回复。我再想想!
& &190 天前
问题解决啦。在指令中$watch 监控model值的变化,根据新值做判断,就可以啦。
& · & 1014 人在线 & 最高记录 1307 & · &
创意工作者们的社区
Lovingly made by OLIVIDA
VERSION: 3.8.3 · 38ms · UTC 01:44 · PVG 09:44 · LAX 18:44 · JFK 21:44? Do have faith in what you're doing.Angularjs 如何在一个控制器中监听浏览器地址的变化并绑定事件?
ps:不是映射到不同的控制器,而是在一个控制器中监听并触发回调函数
如果另外的页面,等同刷新了,貌似没啥方案。如果你是通过 $route 实现的多个 View,可使用该事件。$rootScope.$on('$routeChangeSuccess', function () {
// write callback here当前访客身份:游客 [
已有文章 2016 篇
当前位置:
如何在 AngularJS 中对控制器进行单元测试
英文原文:
0人收藏此文章,
推荐于 1年前 (共 8 段, 翻译完成于 12-17) ()
参与翻译(2人):
开发者们都一致认为单元测试在开发项目中十分有好处。它们帮助你保证代码的质量,从而确保更稳定的研发,即使需要重构时也更有信心。
测试驱动开发流程图
AngularJS的代码声称其较高的可测性确实是合理的。单单文档中列出端对端的测试实例就能说明。就像AngularJS这样的项目虽然都说单元测试很简单但真正做好却不容易。即使官方文档中以提供了详尽的实例,但在我的实际应用中却还是很有挑战。这里我就简单示范一下我是怎么操作的吧.
&翻译的不错哦!
Instant Karma
&是来Angular团队针对JavaScript开发的一个测试运行框架。它很方便的实现了自动执行测试任务从而替代了繁琐的手工操作(好比回归测试集或是加载目标测试的依赖关系)Karma 和Angular的协作就好比花生酱和果冻.
只需要在Karma中定义好配置文件启动它,接下来它就会在预期的测试环境下的自动执行测试用例。你可以在配置文件中制定相关的测试环境。,是我强烈推荐的可以快速实施的方案。在我近期的项目中Karma 的配置如下:
module.exports = function(config) {
config.set({
basePath: '../',
'app/lib/angular/angular.js',
'app/lib/angular/angular-*.js',
'app/js/**/*.js',
'test/lib/recaptcha/recaptcha_ajax.js',
'test/lib/angular/angular-mocks.js',
'test/unit/**/*.js'
exclude: [
'app/lib/angular/angular-loader.js',
'app/lib/angular/*.min.js',
'app/lib/angular/angular-scenario.js'
autoWatch: true,
frameworks: ['jasmine'],
browsers: ['PhantomJS'],
plugins: [
'karma-junit-reporter',
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-jasmine',
'karma-phantomjs-launcher'
junitReporter: {
outputFile: 'test_out/unit.xml',
suite: 'unit'
&翻译的不错哦!
这个跟的默认配置类似只不过有以下几点不同:
需要更改浏览器从Chrome 转到,&这样每次跳转时无需再打开新的浏览器窗口,但在OSX系统会有窗口延迟。所以这个插件还有浏览器设置都做了更改。
由于我的应用需要引用Google的Recaptcha服务因此添加了依赖的recaptcha_ajax.js小文件。这个小配置就像在Karma的配置文件中添加一行代码那么简单。
autoWatch确实是个很酷的设置,它会让Karma在有文件更改时自动回归你的测试用例。你可以这样安装Karma:
npm install karma
&提供了一个简单的脚本inscripts/test.sh去触发Karma的测试。
&翻译的不错哦!
用Jasmine设计测试用例
当使用----一种行为驱动开发模式的JavaScript测试框架为Angular设计单元测试用例时大部分的资源都已可获取。
这也就是我接下来要说的话题。
如果你要对AngularJS controller做单元测试可以利用Angular的依赖注入&功能导入测试场景中controller需要的服务版本还能同时检查预期的结果是否正确。例如,我定义了这个controller去高亮需要导航去的那个页签:
app.controller('NavCtrl', function($scope, $location) {
$scope.isActive = function(route) {
return route === $location.path();
&翻译的不错哦!
如果想要测试isActive方法,我会怎么做呢?我将检查$locationservice 变量是否返回了预期值,方法返回的是否预期值。因此在我们的测试说明中我们会定义好局部变量保存测试过程中需要的controlled版本并在需要时注入到对应的controller当中。然后在实际的测试用例中我们会加入断言来验证实际的结果是否正确。整个过程如下:
describe('NavCtrl', function() {
var $scope, $location, $rootScope, createC
beforeEach(inject(function($injector) {
$location = $injector.get('$location');
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
var $controller = $injector.get('$controller');
createController = function() {
return $controller('NavCtrl', {
'$scope': $scope
it('should have a method to check if the path is active', function() {
var controller = createController();
$location.path('/about');
expect($location.path()).toBe('/about');
expect($scope.isActive('/about')).toBe(true);
expect($scope.isActive('/contact')).toBe(false);
使用整个基本的结构,你就能设计各种类型的测试。由于我们的测试场景使用了本地的环境来调用controller,你也可以多加上一些属性接着执行一个方法清除这些属性,然后再验证一下属性到底有没有被清除。
&翻译的不错哦!
$httpBackendIs Cool
那么要是你在调用$httpservice请求或是发送数据到服务端呢?还好,Angular提供了一种
$httpBackend的mock方法。这样的话,你就能自定义服务端的响应内容,又或是确保服务端的响应结果能和单元测试中的预期保持一致。
具体细节如下:
describe('MainCtrl', function() {
var $scope, $rootScope, $httpBackend, $timeout, createC
beforeEach(inject(function($injector) {
$timeout = $injector.get('$timeout');
$httpBackend = $injector.get('$httpBackend');
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
var $controller = $injector.get('$controller');
createController = function() {
return $controller('MainCtrl', {
'$scope': $scope
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
it('should run the Test to get the link data from the go backend', function() {
var controller = createController();
$scope.urlToScrape = '';
$httpBackend.expect('GET', '/slurp?urlToScrape=http:%')
.respond({
"success": true,
"links": ["", "http://angularjs.org", ""]
// have to use $apply to trigger the $digest which will
// take care of the HTTP request
$scope.$apply(function() {
$scope.runTest();
expect($scope.parseOriginalUrlStatus).toEqual('calling');
$httpBackend.flush();
expect($scope.retrievedUrls).toEqual(["", "http://angularjs.org", ""]);
expect($scope.parseOriginalUrlStatus).toEqual('waiting');
expect($scope.doneScrapingOriginalUrl).toEqual(true);
正如你所见,beforeEach call其实都很类似,唯一不同的是我们是从injector获取$httpBackend而并非直接获取。即使如此,创建不同的测试时还会有一些明显的不同之处。对初学者来说,会有一个afterEachcall 方法来确保$httpBackend在每次用例执行后不会有明显的异常请求。如果你观察一下测试场景的设置和$httpBackend方法的应用就会会发现有那么几点不是那么直观的。
&翻译的不错哦!
实际上调用$httpBackend的方法也算是简单明了但还不够——我们还得在传值给$scope.$apply的方法中把调用封装到实际测试中的$scope.runTest方法上。这样在$digest被触发后才能处理HTTP请求。而如你所见直到我们调用$httpBackend.flush()方法后$httpBackend才会被解析,这也就保证了我们能在调用过程中去验证返回的结果是否正确(在上面的示例中,controller的$scope.parseOriginalUrlStatusproperty属性将被传递给调用者,我们也因此能实时监控)
接下来的几行代码都是在调用过程中检测$scopethat属性的断言。很酷吧?
提示:在某些单元测试中,用户习惯把没有$的范围标记为变量。这个在Angular文档中并没有强制要求或是过分强调,只是我在使用中为了提高可读性和一致性才使用$scopelike这种方式。
&翻译的不错哦!
也许这就是我做起来对其他人而言只是自然而然能做到的事情之一,但是学习使用Angular编写单元测试一开始对我而言确实是相当痛苦的。我发现自己对如何开始的理解大多来自互联网上各种博客文章和资源的拼拼凑凑,没有真正一致或明确的最佳实践,而是通过自然而然随意的选择。我想针对我最终得到的成果提供一些文档,以帮助那些也许还在坑里面挣扎的其他人,毕竟他们只是想要编写代码而已,而非不得不去了解Angular和Jasmine中所有的怪异特性和独特用法。因此我希望这篇文章能对你有些许帮助。
&翻译的不错哦!
这个google的angular js 最近有点火}

我要回帖

更多关于 angularjs单元测试 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信