基于karma和jasmine的Angularjs 单元测试

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();

时间: 2024-10-12 22:23:32

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

基于Karma和Jasmine的AngularJS测试

1:工程目录结构 [email protected]:karma-t01$ tree -L 3.├── client│   ├── app│   │   └── user│   ├── bower_components│   │   ├── angular│   │   ├── angular-mocks│   │   └── angular-resource│   └── bower.json├── karma.conf.js└── readme 7 directories, 3 files

Angularjs 基于karma和jasmine的单元测试

目录: 1. 单元测试的配置 2. 实例文件目录解释 3. 测试controller     3.1 测试controller中变量值是否正确     3.2 模拟http请求返回值,测试$http服务相关 4. 从文件中读取json,来模拟 http请求返回数据 5. 测试返回promise的service 已经有很多教程提到了angularjs项目的单元测试,但大都不是很全,如一些入门的文章,介绍了测试http service 却没有介绍如何从文件中读取测试数据来仿真.一些介绍如何从文件中读

基于Karma 和 Jasmine 的Angular 测试(持续更新中)

最近对前端测试较感兴趣,尤其是Nodejs + Karma + Jasmine 对Angular 的测试.到处看看,做个记录吧,断断续续的更新. <一> 用Jasmine 测试 Angular 的service 1. 先扔代码吧: var app = angular.module('Application', []); app.factory('myService', function(){     var service  = {};     service.one  = 1;     se

利用Karma、Jasmine 做前端单元测试

<一> 使用技术 karma jasmine karma-coverage <二> 安装插件 1.nodejs 2.安装karma npm install -g karma npm install -g karma-cli 3.安装jasmine npm install -g jasmine 4.安装karma-coverage npm install -g karma-coverage <三>跑起一个程序 1.项目的目录结构: 2.add.js 文件 function

结合angularjs,Karma和Jasmine自动化单元测试

前言 在Java领域,Apache, Spring, JBoss 三大社区的开源库,包罗万象,但每个库都在其领域中都鹤立鸡群.而Nodejs中各种各样的开源库,却让人眼花缭乱,不知从何下手. Nodejs领域: Jasmine做单元测试,Karma自动化完成单元测试,Grunt启动Karma统一项目管理,Yeoman最后封装成一个项目原型模板,npm做nodejs的包依赖管理,bower做javascript的包依赖管理. Java领域:JUnit做单元测试, Maven自动化单元测试,统一项目

Karma和Jasmine自动化单元测试

前言 在Java领域,Apache, Spring, JBoss 三大社区的开源库,包罗万象,但每个库都在其领域中都鹤立鸡群.而Nodejs中各种各样的开源库,却让人眼花缭乱,不知从何下手. Nodejs领域: Jasmine做单元测试,Karma自动化完成单元测试,Grunt启动Karma统一项目管理,Yeoman最后封装成一个项目原型模板,npm做nodejs的包依赖管理,bower做javascript的包依赖管理.Java领域:JUnit做单元测试, Maven自动化单元测试,统一项目管

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

1. Karma的介绍 Karma是Testacular的新名字,在2012年google开源了Testacular,2013年Testacular改名为Karma.Karma是一个让人感到非常神秘的名字,表示佛教中的缘分,因果报应,比Cassandra这种名字更让人猜不透! Karma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner).该工具可用于测试所有主流Web浏览器,也可集成到CI(Continuous integration)工具,也可和其他代

AngularJs单元测试

这篇文章主要介绍了angularJS中的单元测试实例,本文主要介绍利用Karma和Jasmine来进行ng模块的单元测试,并用Istanbul  来生成代码覆盖率测试报告,需要的朋友们可以参考下,以下可全都是干货哦! 当ng项目越来越大的时候,单元测试就要提上日程了,有的时候团队是以测试先行,有的是先实现功能,后面再测试功能模块,这个各有利弊,今天主要说说利用karma和jasmine来进行ng模块的单元测试. 一.Karma+Jasmine+ Istanbul Karma是Testacular

基于spring-boot的应用程序的单元测试方案

概述 本文主要介绍如何对基于spring-boot的web应用编写单元测试.集成测试的代码. 此类应用的架构图一般如下所示: 我们项目的程序,对应到上图中的web应用部分.这部分一般分为Controller层.service层.持久层.除此之外,应用程序中还有一些数据封装类,我们称之为domain.上述各组件的职责如下: Controller层/Rest接口层: 负责对外提供Rest服务,接收Rest请求,返回处理结果. service层: 业务逻辑层,根据Controller层的需要,实现具体