Angularjs 基于karma和jasmine的单元测试
目录:
1. 单元测试的配置
2. 实例文件目录解释
3. 测试controller
3.1 测试controller中变量值是否正确
3.2 模拟http请求返回值,测试$http服务相关
4. 从文件中读取json,来模拟 http请求返回数据
5. 测试返回promise的service
已经有很多教程提到了angularjs项目的单元测试,但大都不是很全,如一些入门的文章,介绍了测试http service 却没有介绍如何从文件中读取测试数据来仿真。一些介绍如何从文件中读取仿真数据的文章对入门则太深入。所以写了这个在工作中经常会遇到的情况的教程。希望有点用:)
1. 单元测试的配置
- 安装 angular
npm install
angular --save - 安装 karma
npm install -g karma --save-dev - 安装 Jasmine
npm install karma-jasmine jasmine-core
--save-dev - 安装 ngMock
npm install angular-mocks --save-dev - 安装 jasmine-jquery
bower install jasmine-jquery --save - 安装 karma-read-json
bower
install karma-read-json - 下载实例
https://github.com/wuhaibo/angularUnitTest
2. 实例文件目录解释

3. 测试controller
首先看看我们的controller的代码
'use strict';
/* Controllers */
/* module */
var unitTestApp = angular.module('unitTestApp', []);
/* Controllers */
unitTestApp.controller('unitTestCtrl', function($scope,$http) { //set name
$scope.name = "william wood"; //通过http请求得到user
$scope.GetUser = function(){
$http.get('/auth.py').then(function(response) {
$scope.user = response.data;
});
};
});
这个controller很简单, 有两个元素
- 在scope里声明了一个变量name, 并赋值 williamwood
- 定义了一个函数GetUser, 这个函数发送一个http get请求,来给scope.user 赋值
我们先测试 1 再测试 2.
3.1 测试controller中变量值是否正确
测试的代码在 /test/unit/controllersSpec.js, 测试代码简单说明如下
'use strict';
//测试类型描述,这里表示测试unitTestApp的controllers
describe('unitTestApp controllers', function() {
//测试类型描述,这里表示测试unitTestCtrl这个controller
describe('unitTestCtrl', function(){ //beforeEach 表示在运行所有测试前的准备工作。
//这里生成unitTestApp 的module
beforeEach(module('unitTestApp')); //定义在测试中会用到的object,以便在整个测试环境中使用
var scope,ctrl; //inject利用angular的依赖注入,将需要的模块,服务插入作用域
beforeEach(inject(function ($controller, $rootScope) {
//模拟生成scope, $rootScope是angular中的顶级scope,angular中每个controller中的
//scope都是rootScope new出来的
scope = $rootScope.$new();
//模拟生成controller 并把先前生成的scope传入以方便测试
ctrl = $controller('unitTestCtrl', {$scope: scope});
})); //测试从这里开始
// it 里'should create name william wood in unitTestCtrl' 说明测试的项目
it('should create name william wood in unitTestCtrl',
inject(function() {
//测试期望 scope.name 的值为 william wood
expect(scope.name).toEqual('william wood');
}));
//测试GetUser函数,详细将在下面介绍
it('GetUser should fetch users', inject(function($injector){
....
}));
});
});
在jasmine中用describe来描述testcase类别(如是测试哪个controller,哪个modular。。。), beforeEach 用来做测试前的准备工作,inject利用angular的依赖注入,将需要的模块,服务插入作用域。真正的测试代码在it函数里,这个函数的第一个参数为testcase描述,第二个函数为测试逻辑.
测试配置(可以跳过这一步)
测试可以用karma init命令配置, 这个命令会生成karma.conf.js 文件来作为测试配置文件。由于实例文件夹中已经有了这个文件就可以跳过这一步。以后可以使用实例文件结构作为其他项目的基础模板。
运行测试
1. Windows commandline 进入到 karma.conf.js 所在目录。
2. 运行指令 karma start, 这时会弹出浏览器窗口,不用管,它们被启动来执行测试,就让他们在后台呆着就可以。 karma会自动监视文件改动自动执行测试。测试成功如下图所示,这里因为在测试文件中有两个测试用例,所以可以看到 Executed 1 of 2 … 字样(为了测试方便,firefox测试平台被注释掉,所有测试将只在chrome上运行,如果要使用firefox来运行测试只需要将karma.conf.js 里的 browsers : ['Chrome'/*, 'Firefox'*/] 改为 browsers : ['Chrome', 'Firefox']即可)

3. 测试失败的情况
修改expect(scope.name).toEqual('william wood')为
expect(scope.name).toEqual('william
wood is me');
保存后切换到命令行窗口,发现测试自动运行了,并有错误报告。

Ok 到此为止我们已经可以测试一个controller了。下面我们介绍如何模拟http请求的返回值测试$http服务相关的逻辑。
3.2 模拟http请求返回值,测试$http服务相关
记得我们在controller中有一个GetUser函数
//通过http请求得到user
$scope.GetUser = function(){
$http.get('/auth.py').then(function(response) {
$scope.user = response.data;
});
这个函数通过http get请求得到user的值。
在单元测试里我们并不真的希望发送一个http get请求来运行测试,因为那样会使测试复杂化,网络相关的各种问题都会导致测试失败,而且angular http服务是异步的,而我们希望测试是同步的。那么怎么做呢?
先来看测试的代码,仍然在 /test/unit/controllersSpec.js
//模拟http get的返回值, 插入injector服务,让我们能够在测试代码中使用依赖注入来获得需要的服务
it('GetUser should fetch users', inject(function($injector){
// $httpBackend 是由angular mock提供的一个模拟http请求返回服务
// 可以用它来模拟http请求的返回值
// 这里通过$injector来获取它的实例
var $httpBackend = $injector.get('$httpBackend'); // $httpBackend 在Get方法,对 '/auth.py' 的url将会返回 一个jason对象
// {customerId: '1',name:'benwei'}
$httpBackend.when('GET', '/auth.py').respond({customerId: '1',name:'benwei'}); //以上为测试前的准备工作, 也可以把这部分代码放在beforeEach里,
//但要注意: beforeEach里的设置将影响所有在它作用域的测试用例。 //运行GetUser函数
scope.GetUser(); //把http的异步转为同步,要求$httpBackend立刻返回数据
$httpBackend.flush(); // 查看scope.user的值是否正确
expect(scope.user).toEqual({customerId: '1',name:'benwei'});
}));
4. 从文件中读取json,来模拟 http请求返回数据
有些时候我们需要返回比较大的json数据, 这时json数据像上面这样写在测试代码里就不大现实。比较可行的方案是把json数据保存在json文件中,并从文件中读取数据。这时我们就需要Karma-Read-JSON的帮助。
我们已经在单元测试的配置中安装了这个插件,并在 /test/karma.conf.js 中做了设置,这里对设置进行简单的说明。(可以跳过阅读这一步,只要记得将模拟使用的 json文件放在 test/mock/ 文件夹中,并且文件后缀为.json)
1.在测试中引入karma-read-json框架
files : [
…
//test framework
'app/bower_components/karma-read-json/karma-read-json.js',
…
],
2. 向karma指定在测试中会用到的模拟数据文件格式,
files : [
…
// fixtures
{pattern: 'test/mock/*.json', included: false},
…
],
注意这里的根目录是在karma.conf.js文件中设置的,如下
basePath : '../', //设置 karma.conf.js所在目录/../ 为根目录
在本实例中模拟数据需要的 json文件应该放在test/mock 文件夹中
当设置进行完后,再来看我们的测试代码
it('GetUser should fetch users mock response from file',
inject(function($injector){
//从文件中读取模拟返回数据
var valid_respond = readJSON('test/mock/data.json');
// 这里通过$injector来获取它的实例获取 httpBackend服务的实例
var $httpBackend = $injector.get('$httpBackend');
// $httpBackend 在Get方法,对 '/auth.py' 的url将会返回
// 一个从test/mock/data.json读取的json对象
$httpBackend.when('GET', '/auth.py').respond(valid_respond);
// $httpBackend 在Get方法,对 '/auth.py' 的url将会返回 一个jason对象
// {customerId: '1',name:'benwei'}
$httpBackend.when('GET', '/auth.py').respond({customerId: '1',name:'benwei'});
//运行GetUser函数
scope.GetUser();
//把http的异步转为同步,要求$httpBackend立刻返回数据
$httpBackend.flush();
// 查看scope.user的值是否正确
expect(scope.user.length).toBe(2);
}));
5. 测试返回promise的service
先来看看service代码,代码可在app\js\services.js 中找到
'use strict';
/* Services */
unitTestApp.factory('GetUserNumberService',
function($http,$q) {
var deferred = $q.defer(); //http 服务请求
$http({method: 'GET', url: '/auth.py'}).then(
function(response){
deferred.resolve(response.data.length);
},
function (response) {
deferred.reject(response);
}
); //返回http 服务请求的promise
return deferred.promise;
}
);
我们创建了一个叫 GetUserNumberService 的服务,这个服务通过发送http请求获得返回数据的长度。这个服务的测试代码如下,代码可在 test\unit\servicesSpec.js 中找到
'use strict';
/* jasmine specs for services go here */ describe('serviceTest', function() { describe('Test GetUserNumberService', function() {
//mock module
beforeEach(module('unitTestApp')); it('GetUserNumberService should return 2',
inject(function($injector) {
//模拟返回数据
var valid_respond = '[{"customerId": "1","name": "benwei"},{"customerId": "2","name": "william"}]';
var $httpBackend = $injector.get('$httpBackend');
$httpBackend.whenGET('/auth.py').respond(valid_respond); // 通过injector得到service,就像在前面的例子中得到$httpBackend一样
var getUserNumberService = $injector.get('GetUserNumberService');
var promise = getUserNumberService;
var userNum;
promise.then(function(data){
userNum = data;
}); //强迫httpBackend返回数据
$httpBackend.flush(); //通过injector得到$rootScope
var $rootScope = $injector.get('$rootScope');
//强迫传递到当前作用域
$rootScope.$apply(); //测试判断userNum是否为2
expect(userNum).toEqual(2);
}));
});
});
有一个值得注意的地方, 为了将变化传递到当前作用域,所以要使用 $rootScope.$apply();
Angularjs 基于karma和jasmine的单元测试的更多相关文章
- 基于karma和jasmine的Angularjs 单元测试
Angularjs 基于karma和jasmine的单元测试 目录: 1. 单元测试的配置 2. 实例文件目录解释 3. 测试controller 3.1 测试controller中变量值是否 ...
- Karma:1. 集成 Karma 和 Jasmine 进行单元测试
关于 Karma 会是一个系列,讨论在各种环境下,使用 Karma 进行单元测试. 本文讨论 karma 集成 Jasmine 进行单元测试. 初始化 NPM 实现初始化 NPM 包管理,创建 pac ...
- 基于Karma和Jasmine的AngularJS测试
1:工程目录结构 y@y:karma-t01$ tree -L 3.├── client│ ├── app│ │ └── user│ ├── bower_components│ │ ...
- Karma和Jasmine 自动化单元测试环境搭建
最近初学AngularJS ,看到的一些教程中经常有人推荐使用Karma+Jasmine来进行单元测试.自己之前也对Jasmine有些了解,jasmine也是一个不错的测试框架. 1. karma介绍 ...
- Karma和Jasmine自动化单元测试
从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发.Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎.chrome浏 ...
- Karma和Jasmine自动化单元测试——本质上还是在要开一个浏览器来做测试
1. Karma的介绍 Karma是Testacular的新名字,在2012年google开源了Testacular,2013年Testacular改名为Karma.Karma是一个让人感到非常神秘的 ...
- 大前端的自动化工厂(5)—— 基于Karma+Mocha+Chai的单元测试和接口测试
一. 前端自动化测试 大多数前端开发者对测试相关的知识是比较缺乏的,一来是开发节奏很快,来不及写,另一方面团队里也配备了"人肉测试机",完全没必要自己来.但随着项目体量的增大,许多 ...
- Karma:2. 集成 Karma 和 mocha 进行单元测试
上一篇文章讨论了如何集成 Karma 和 Jasmine,地址见:Karma:1. 集成 Karma 和 Jasmine 进行单元测试 这篇文章讨论如何 Karma 集成 mocha 测试框架. 安装 ...
- karma、jasmine做angularjs单元测试
引用文:karma.jasmine做angularjs单元测试 karma和jasmine介绍 <1>技术介绍 karma karma是Testacular的新名字 karma是用来自动化 ...
随机推荐
- 基于Predictive Parsing的ABNF语法分析器(十)——AbnfParser文法解析器之数值类型(num-val)
ANBF语法中的数值类型有3种:二进制.十进制和十六进制,可以是一个以点号分隔的数列,也可以是一个数值的范围.例如,%d11.22.33.44.55表示五个有次序的十进制数字“11.22.33.44. ...
- hao947 : Mybatis resultMap配置插入和主键自增返回 : 好947
映射配置文件 好947 <!-- type:映射实体类的数据类型 id:resultMap的唯一标识 --> <resultMap type="person" ...
- Nubia Z5S 基于官方H207/4.4内核的Mokee4.4.4 RC3.2 (2014.7.31修复呼吸灯(能亮依旧不能呼吸))
特别感谢 yun3195 和 轻描淡写Yhw 帮忙測试 转帖请务必注明本链接地址: http://blog.csdn.net/syhost/article/details/36444259 此ROM ...
- hadoop namanodejava
最近突然想看下hadoop源码,有利于处理一些突发问题.先从name启动开始, NameNode.java public static void main(String argv[]) throws ...
- 当try和finally里都有return时,会忽略try的return,而使用finally的return
今天去逛论坛 时发现了一个很有趣的问题: 谁能给我我解释一下这段程序的结果为什么是:2.而不是:3 代码如下: class Test { public int aaa() { int x = 1; t ...
- Spark&Spark性能调优实战
Spark特别适用于多次操作特定的数据,分mem-only和mem & disk.当中mem-only:效率高,但占用大量的内存,成本非常高;mem & disk:内存用完后,会自己主 ...
- ubuntu12.04安装搜狗输入法配置,安装packettracer字体设置,软件推荐
装上系统,后的各种配置,各种出错之后的解决. 一.安装搜狗输入法 如果系统以前安装了先卸载: sudo apt-get remove fcitx* #删除配置文件 sudo apt-get purge ...
- [Cocos2d-x]Mac下运行HelloCpp For Android
2013年12月22日 一.简介: Mac下运行Cocos2d-x的samples和新建的HelloCocos2dx项目 二.内容: 环境: OS:mac OS X 10.9.1 IDE:Androi ...
- VMware vSphere服务器虚拟化实验十五 vCenter vShield Manager
VMware vSphere服务器虚拟化实验十五 vCenter vShield Manager VMware vShield Manager是专为 VMware vCenter Server 集成 ...
- 【linux驱动分析】之dm9000驱动分析(六):dm9000_init和dm9000_probe的实现
一.dm9000_init 打印出驱动的版本,注冊dm9000_driver驱动,将驱动加入到总线上.运行match,假设匹配,将会运行probe函数. 1 static int __init 2 d ...