Angularjs 基于karma和jasmine的单元测试

目录:

1. 单元测试的配置

2. 实例文件目录解释

3. 测试controller

    3.1 测试controller中变量值是否正确

    3.2 模拟http请求返回值,测试$http服务相关

4. 从文件中读取json,来模拟 http请求返回数据

5. 测试返回promise的service

已经有很多教程提到了angularjs项目的单元测试,但大都不是很全,如一些入门的文章,介绍了测试http service 却没有介绍如何从文件中读取测试数据来仿真。一些介绍如何从文件中读取仿真数据的文章对入门则太深入。所以写了这个在工作中经常会遇到的情况的教程。希望有点用:)

1. 单元测试的配置

  1. 安装 angular
        npm install angular --save
  2. 安装 karma 
      npm install -g karma --save-dev
  3. 安装 Jasmine
        npm install karma-jasmine jasmine-core --save-dev
  4. 安装 ngMock
        npm install angular-mocks --save-dev
  5. 安装 jasmine-jquery
        bower install jasmine-jquery --save
  6. 安装 karma-read-json
        bower install karma-read-json
  7. 下载实例 
    https://github.com/wuhaibo/angularUnitTest

2. 实例文件目录解释

3. 测试controller

首先看看我们的controller的代码

 1  'use strict'; 
2 /* Controllers */
3 /* module */
4 var unitTestApp = angular.module('unitTestApp', []);
5  
6 /* Controllers */
7 unitTestApp.controller('unitTestCtrl', function($scope,$http) {
8
9 //set name
10 $scope.name = "william wood";
11
12 //通过http请求得到user
13 $scope.GetUser = function(){
14 $http.get('/auth.py').then(function(response) {
15 $scope.user = response.data;
16 });
17 };
18 });

这个controller很简单, 有两个元素

  1. 在scope里声明了一个变量name, 并赋值 williamwood
  2. 定义了一个函数GetUser, 这个函数发送一个http get请求,来给scope.user 赋值

我们先测试 1 再测试 2.

3.1 测试controller中变量值是否正确

测试的代码在  /test/unit/controllersSpec.js, 测试代码简单说明如下

 1 'use strict';
2  
3 //测试类型描述,这里表示测试unitTestApp的controllers
4 describe('unitTestApp controllers', function() {
5  
6 //测试类型描述,这里表示测试unitTestCtrl这个controller
7 describe('unitTestCtrl', function(){
8
9 //beforeEach 表示在运行所有测试前的准备工作。
10 //这里生成unitTestApp 的module
11 beforeEach(module('unitTestApp'));
12
13 //定义在测试中会用到的object,以便在整个测试环境中使用
14 var scope,ctrl;
15
16 //inject利用angular的依赖注入,将需要的模块,服务插入作用域
17 beforeEach(inject(function ($controller, $rootScope) {
18 //模拟生成scope, $rootScope是angular中的顶级scope,angular中每个controller中的
19 //scope都是rootScope new出来的
20 scope = $rootScope.$new();
21 //模拟生成controller 并把先前生成的scope传入以方便测试
22 ctrl = $controller('unitTestCtrl', {$scope: scope});
23 }));
24
25 //测试从这里开始
26 // it 里'should create name william wood in unitTestCtrl' 说明测试的项目
27 it('should create name william wood in unitTestCtrl',
28 inject(function() {
29 //测试期望 scope.name 的值为 william wood
30 expect(scope.name).toEqual('william wood');
31 }));
32  
33 //测试GetUser函数,详细将在下面介绍
34 it('GetUser should fetch users', inject(function($injector){
35 ....
36 }));
37 });
38 });
39  

在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函数

1 //通过http请求得到user
2 $scope.GetUser = function(){
3 $http.get('/auth.py').then(function(response) {
4 $scope.user = response.data;
5 });

这个函数通过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();

基于karma和jasmine的Angularjs 单元测试的更多相关文章

  1. karma、jasmine做angularjs单元测试

    引用文:karma.jasmine做angularjs单元测试 karma和jasmine介绍 <1>技术介绍 karma karma是Testacular的新名字 karma是用来自动化 ...

  2. 基于Karma和Jasmine的AngularJS测试

    1:工程目录结构 y@y:karma-t01$ tree -L 3.├── client│   ├── app│   │   └── user│   ├── bower_components│   │ ...

  3. Angularjs 基于karma和jasmine的单元测试

    目录: 1. 单元测试的配置 2. 实例文件目录解释 3. 测试controller     3.1 测试controller中变量值是否正确     3.2 模拟http请求返回值,测试$http服 ...

  4. Karma和Jasmine 自动化单元测试环境搭建

    最近初学AngularJS ,看到的一些教程中经常有人推荐使用Karma+Jasmine来进行单元测试.自己之前也对Jasmine有些了解,jasmine也是一个不错的测试框架. 1. karma介绍 ...

  5. 在WebStorm中集成Karma+jasmine进行前端单元测试

    在WebStorm中集成Karma+jasmine进行前端单元测试 前言 好久没有写博了,主要还是太懒=.=,有点时间都去带娃.看书了,今天给大家分享一个原创的小东西,如果大家对TDD或者BDD有兴趣 ...

  6. 搭建Karma+Jasmine的自动化单元测试

    最近在打算将以前的代码进行重构,过程中发现自己不写自动化测试代码,而是手动的写,这样并不好,所以就学了Karma+Jasmine的自动化单元测试,以后写代码尽量要写自动化单元测试,也要测一下istan ...

  7. Karma和Jasmine自动化单元测试

    从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发.Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎.chrome浏 ...

  8. Karma和Jasmine自动化单元测试——本质上还是在要开一个浏览器来做测试

    1. Karma的介绍 Karma是Testacular的新名字,在2012年google开源了Testacular,2013年Testacular改名为Karma.Karma是一个让人感到非常神秘的 ...

  9. Karma:1. 集成 Karma 和 Jasmine 进行单元测试

    关于 Karma 会是一个系列,讨论在各种环境下,使用 Karma 进行单元测试. 本文讨论 karma 集成 Jasmine 进行单元测试. 初始化 NPM 实现初始化 NPM 包管理,创建 pac ...

随机推荐

  1. CAS 单点登录

    首先,何谓单点登录. 单点登录(Single Sign On),简称为 SSO,是眼下比較流行的企业业务整合的解决方式之中的一个. SSO的定义是在多个应用系统中,用户仅仅须要登录一次就能够訪问全部相 ...

  2. Android编程心得-Handler与子线程的交互初步

    在编写项目的时候,本人发现一个关于线程与Handler很容易犯的错误. 我有两个Activity,一个Activity在后台创建了一个线程并且启动,这个线程对象对应的实体实在另外一个Activity的 ...

  3. opencv做的美女找茬程序~

    // CMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <cv.h> #include <high ...

  4. 循环灯控制器,该控制器控制红、绿、黄三个发光管循环发亮(VHDL语言)

    设计一个循环灯控制器,该控制器控制红.绿.黄三个发光管循环发亮.要求红发光管亮2秒,绿发光管亮3秒,黄发光管亮1秒.(假设外部提供频率为1MHz的方波信号) library ieee; use iee ...

  5. vs2008编译QT开源项目三国杀(五篇文章)

    请参看 http://tieba.baidu.com/f?kz=1508964881 按照上面的网址教程,下载三国杀源码,swig工具,并下载最新的QT4.8.2 for vs2008.我本机已经安装 ...

  6. C++的for循环细节,必看!

    C++中.For(A;B;C)   C语句是在每次循环后才运行. 如: y=10; for( i=0;i<10;y=++i) {    cout<<y<<endl; } ...

  7. 使用AjaxFileUpload.js实现文件异步上�

    ajax是无法提交文件的,所以在上传图片并预览的时候,我们常常使用Ifame的方法实现看似异步的效果.可是这样总不是非常方便的,AjaxFilleUpload.js对上面的方法进行了一个包装,使得我们 ...

  8. 二分查找(非递归JAVA)

    庞果网编程英雄会上做的一道题:二分查找(非递归),和大家分享一下: public class BinarySearchClass { public static int binary_search(i ...

  9. codeforces 577

    codeforces 577A 题目链接:http://codeforces.com/problemset/problem/577/A 题目大意:给出一个n*n的表格,每个表格对应的值为横坐标*纵坐标 ...

  10. mysql 高可用方案MHA介绍

    概述 MHA是一位日本MySQL大牛用Perl写的一套MySQL故障切换方案,来保证数据库系统的高可用.在宕机的时间内(通常10—30秒内),完成故障切换,部署MHA,可避免主从一致性问题,节约购买新 ...