如何测试 Controller - Angularjs

AngularJS中的一个典型的Controller 在AngularJS中,Controller主要用于hold一些跟view的有关的状态,以及数据模型,比如界面上某些元素是否展示,以及展示那些内容等。通常来说,Controller会依赖与一个Service来提供数据: app.controller('EventController', ['$scope', 'EventService', function($scope, EventService) { EventService.getEvents().then(function(events) { $scope.events = events; }); }]); 而service本身则需要通过向后台服务发送请求来获取数据: app.factory('EventService', ['$http', '$q', function($http, $q) { return { getEvents: function() { var deferred = $q.defer(); $http.get('/events.json').success(function(result) { deferred.resolve(result); }).error(function(result) { deferred.reject(result); }); return deferred.promise; } }; }]); 通常的做法是返回一个promise对象,然后当数据准备完整之后,controller的then会被执行。 那么对于这种情况(在AngularJS中,算是一个非常典型的场景),我们如何进行单元测试呢? 测试依赖与Service的Controller 通常来讲,在单元级别的测试中,我们肯定不希望Service真正的发送请求,这样就变成了集成测试,而且前端的开发完全依赖与后台的开发进度/稳定程度等。 所以我们需要做一个假的Service,这个假的Service仅仅在测试中存在: var app = angular.module('MyApp'); describe("EventController", function() { var scope, q; var controllerFactory; var mockSerivce = {}; var events = ["Event1", "Event2", "Event3"]; beforeEach(function() { module("MyApp"); inject(function($rootScope, $controller, $q) { controllerFactory = $controller; scope = $rootScope....

December 28, 2013 1 min

依赖管理器Bower简介

Bower简介 Bower安装及简单配置 Bower是一个基于Node.js的依赖管理工具,它是一个npm的包,因此安装十分简单,由于我们需要在所有项目中都可以使用bower,因此将其安装在全局目录下: $ npm install -g bower 安装完成之后,可以通过bower search来搜索需要的包,比如: $ bower search underscore 典型的应用场景可能会是这样的,新建一个项目目录,然后运行bower init: $ mkdir -p listing $ cd listing $ bower init 和Grunt类似,bower会问你一些问题,比如项目名称,项目入口点,作者信息之类: { "name": "listing", "version": "0.0.0", "authors": [ "Qiu Juntao <juntao.qiu@gmail.com>" ], "main": "src/app.js", "license": "MIT", "ignore": [ "**/.*", "node_modules", "bower_components", "test", "tests" ] } 比如我们需要安装jQuery和underscore.js,则很简单的运行bower install命令即可: $ bower install jquery $ bower install underscore 如果需要团队中的其他成员可以在本地恢复我们的环境,需要在bower.json中指定dependencies小节: "dependencies": { "jquery": "~2.0.3", "underscore": "~1.5.2" } 所有的JavaScript包都被安装到了本地的bower_components目录下,如果有了bower....

October 9, 2013 1 min

Grunt常用插件

Grunt的几个常用插件 grunt-karma 简介 grunt-karma是一个karma的Grunt插件,上一篇文章中已经介绍了karma的基本用法。这里简单介绍如何在Grunt中使用karma。 首先需要安装grunt-karma插件: $ npm install grunt-karma --save-dev 然后在Gruntfile.js中加载该插件: grunt.loadNpmTasks('grunt-karma'); 在使用karma之前,需要生成一个karma的配置文件karma.conf.js: $ karma init karma.conf.js 然后在Gruntfile.js中,加入初始化karma的参数,并指定,karma需要使用karma.conf.js文件作为配置来运行: grunt.initConfig({ karma: { unit: { configFile: 'karma.conf.js' } } }); 大多数情况下,如果要把karma作为CI的一部分,应该启动单次运行模式: singleRun: true 这样karma会启动浏览器,运行所有的测试用例,然后退出。 grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-karma'); grunt.registerTask('default', ['jshint', 'karma']); 注意此处的default后边带了一个任务数组,其中每个任务会按照声明的顺序依次被执行。事实上此处的’default’是后边整个列表的一个别名(alias)。 grunt-jshint / grunt-uglify / grunt-concat grunt-contrib-jshint是一个用于JavaScript静态语法检查的工具,它会帮助开发者在进行较为严格的语法检查。 和其他的Grunt插件一样,它是以一个npm的包的形式发布的,因此安装非常容易: $ npm install grunt-contrib-jshint --save-dev 然后在Gruntfile.js中加载该插件: grunt.loadNpmTasks('grunt-contrib-jshint'); 即可,类似的还有:用以连接所有JavaScript源代码为一个独立文件的grunt-contrib-concat,以及用以最小化JavaScript源码的grunt-contrib-uglify。 自定义插件 grunt-init是一个帮助开发人员快速搭建基于Grunt项目的工具,比如开发jQuery插件,Gruntfile,或者Grunt插件本身。安装方式很简单,我们需要在其他项目也用到grunt-init,因此安装在全局路径下-g: $ npm install -g grunt-init 开发Grunt插件,我们需要一个基本的模板,将这个模板clone到home下的.grunt-init目录下: $ git clone git://github.com/gruntjs/grunt-init-gruntplugin.git ~/.grunt-init/gruntplugin 然后新建一个目录,并在该目录下运行: $ mkdir beautify $ cd beautify $ grunt-init gruntplugin grunt-init会让你回答一些问题,比如插件名称,版本号,github链接等。之后,grunt-init会生成一个基本的模板,开发者只需要完成自己插件的逻辑代码即可。逻辑实现在tasks/<plugin-name>....

October 8, 2013 1 min

使用Karma作为JavaScript的测试Runner

Karma 简介 Karma是一个JavaScript的测试运行器。事实上,Karma更是一个测试环境,使用Karma可以很方便的的运行测试(方便到你感觉不到它的实际存在)。 一般的TDD的开发流程为: 编写测试(一个会失败的case) 运行测试,并看到这个测试失败 编写代码(足够让测试通过的代码) 运行测试,并看到测试通过 重构 运行测试,并看到测试通过 然后如此循环,而在前端开发中,很长一段时间,这个流程受限于开发环境,比如添加了一个新的JavaScript源文件,开发者需要在HTML中引入相应地文件,以及响应的测试文件,然后刷新页面(有时候还需要清空浏览器缓存)。 在这个过程中,开发者真正关注的就是编写测试,运行测试,编写实现,重构等等,需要不断的重复这个过程。而不是关注如刷新页面,清空缓存,修改HTML对脚本的引用等武馆的工作。 Karma就是这样一个开发环境,开发者指定需要测试的脚本/测试文件,需要运行的浏览器等信息,Karma会在后台自动监控文件的修改,并启动一个浏览器与Karma的服务器连接,这样当源代码或者测试发生修改后,Karma会自动运行测试。 开发者可以指定不同的浏览器,甚至可以跨设备。由于Karma只是一个运行器,你可以使用项目中正在使用的测试框架如Jasmine,QUnit等,甚至可以自定义适配器来支持你自己的测试框架。 运行Karma Karma需要一个配置文件来知道哪些文件需要被加载,需要被监控(当文件内容发生变化时,尝试运行测试),这个配置文件可以通过Karma自带的参数来生成。 基本使用 Karma被实现为一个npm的包,所以可以通过 $ npm install -g karma 安装之后,可以生成karma需要的配置文件: $ karma init my.conf.js karma会让你回答一些问题,比如是哪种测试框架,哪些文件需要被测试,哪些浏览器需要被考虑等。生成的配置文件的一个片段是: // base path, that will be used to resolve files and exclude basePath = ''; // list of files / patterns to load in the browser files = [ JASMINE, JASMINE_ADAPTER, 'src/**/*.js', 'test/**/*spec.js' ]; // web server port port = 9876; // browsers browsers = ['Chrome']; 更新 新的配置文件生成脚本会生成更加模块化的配置:...

October 8, 2013 1 min

Grunt 101 - JavaScript里的构建工具

Grunt简介 Grunt是一个基于JavaScript的构建工具。和其他的构建工具类似,grunt主要用于一些将一些繁琐的工作自动化,比如运行测试,代码的静态检查,压缩JavaScript源代码等等。 安装grunt-cli 要在命令行运行grunt,需要安装grunt的命令行工具: $ npm install -g grunt-cli grunt-cli本身并不会提供Grunt构建工具,而只是一个Grunt的调用器。-g参数表示将grunt-cli安装在全局的路径中,这样我们可以在不同的项目中使用grunt-cli,而由于grunt-cli本身只是一个调用器,所以对于不同的项目,真正运行的Grunt可以是不同的版本,而命令行的借口则完全一致。 grunt-cli提供的命令行可执行文件的名称为grunt,这个工具每次运行时都会检查当前目录下的Grunt。 使用grunt-cli 如果在一个既有的npm模块中,可以很容易的加入grunt的支持,只需要修改package.json,加入依赖,然后运行npm install来完成依赖的安装即可。 如果是一个新启动的项目,那么在项目中添加两个文件:package.json和Gruntfile。其中package.json用来定义当前项目是一个npm的模块,而Gruntfile用来定义具体的任务,以及加载Grunt的其他插件(Grunt提供丰富的插件,比如运行测试,代码静态检查等功能都是通过插件来完成的) package.json package.json定义了一个工程的元数据,这些数据被npm管理器来使用,npm本身提供了init参数可以很容易的生成一个package.json文件: $ npm init 根据提示可以很容易的生成一个新的package.json { "name": "chapter-testing", "version": "0.0.0", "description": "This is the demo for how to use grunt.js", "main": "my.conf.js", "directories": { "test": "test" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Juntao", "license": "BSD-2-Clause" } 一般来说,package.json文件中有一个devDependencies的小节,定义了本项目的外部依赖。 可以通过运行 $ npm install grunt --save-dev 来为工程文件package.json添加devDependencies小节的定义: "devDependencies": { "grunt": "~0....

October 7, 2013 1 min