使用Jasmine和Karma对AngularJS页面程序进行测试

AngularJS是继jQuery之后发生在JavaScript上最好的东西。这也是JavaScript开发一直以来想要的方式。Angular主要的优点之一就是它的依赖注入(Dependency Injection),它非常利于代码的单元测试。但有点小怪异的是,我在无论如何都没能找到一个介绍如何做单元测试的教程。

当然有很多不错的推荐:使用Jasmine测试框架和Karma测试执行器(Test Runner);但是并没有一篇完整的从无到有指导如何测试的教程。所以我写了这篇文章。我在网上找了很多资源才知道如何去做,而你现在不需要去做这些(如果一开始就看到这篇文章的话)。

请告诉我你看到的任何错误,直到我能说这是基于Karma和Jasmine测试Angular应用的最佳实践。

介绍

这篇文章会引导你安装使用Karma和Jasmine做自动化测试所需要的所有工具。我不在乎你实在使用TDD(测试驱动开发)还是TAD(测试辅助开发),在这篇文章中,我假设你已经有一个文件需要测试。

安装Karma

如果你没有安装 Node.js,那么请自行下载和安装。安装之后,打开终端或命令行输入一下命令:

npm install -g karma

文件结构

文件结构是跟我们的议题关联不大,但是在接下来的测试中,我使用的文件结构如下:

Application
| angular.js
| angular-resource.js
| Home
 | home.js
| Tests
 | Home
 | home.tests.js
 | karma.config.js (will be created in the next step)
 | angular-mocks.js

*我并不主张这种文档结构,我展示它只是为了测试举例。

配置Karma

切换到你想要放置配置文件的目录,然后在终端中输入下面的命令来创建配置文件:

karma init karma.config.js

你会被询问一些问题,包括你想使用那个测试框架,你是否需要自动监测文件,包含哪些测试和被测试文件等。在我们的教程中,我们保留‘Jasmine'作为我们默认的框架,开启文件自动监测,并包含下面的文件:

../*.js
../**.*.js
angular-mocks.js
**/*.tests.js

这些都是相对路径,包含了1)父目录下的所有.js文件,2)父目录下的所有子目录下的所有.js文件,3)当前目录下的angular-mock.js,4)以及当前目录(包含子目录)下所有的.tests.js文件(我喜欢以这样的方式来区分测试文件和其他的文件)。

不管你选择了什么文件,请确保你引入了 angular.js,angular-mock.js,以及其他你需要使用的文件。

启动Karma

现在已经可以启动Karma了,依然在终端中输入:

karma start karma.config.js

这个命令会在你的电脑上启动你在配置文件中列出的浏览器。这些浏览器都会以socket的方式连接到Karma的实例上,你会看到一组活动的浏览器并被告知她们是否在执行测试。我但愿Karma已经告诉你在每个浏览器上的最终测试结果总结(比如16个中的15个通过,1个失败),遗憾的是你只能通过终端窗口看到这些信息。

Karma的一个很突出的特色是你可以在网络中使用任何设备连接并测试你的代码。试一下将你的手机浏览器指向Karma服务,你可以在电脑上任何一个运行的浏览器上找到这个测试的URL地址。它应该类似于:http://localhost:9876/?id=5359192。你可以将你的手机,虚拟机,或其他任何设备的浏览器指向 [你在网络上的IP地址]:9876/?id=5359192. 因为Karma是在运行一个 Node.js 实例,你的测试机器就像一个web服务器一样,会将测试发送到任何指向它的浏览器。

基本的测试

我们假设你已经有一个文件需要测试。我们要使用到的 home.js 文件如下:

home.js

'use strict';

var app = angular.module('Application', ['ngResource']);

app.factory('UserFactory', function($resource){
 return $resource('Users/users.json')
});

app.controller('MainCtrl', function($scope, UserFactory) {
 $scope.text = 'Hello World!';
 $scope.users = UserFactory.get();
});

我们可以在 home.test.js 文件中创建我们的测试用例。我们从简单的那个测试开始:$scope.text 应该等于 ‘Hello World!'。 为了完成这个测试,我们需要模拟我们的 Application 模块以及 $scope 变量。我们会在Jasmine的 beforeEach 方法中做这个工作,这样的话我们在每个测试用例开始时可以有一个全新的(干净的)controler和scope对象。

home.tests.js

'use strict';

describe('MainCtrl', function(){
 var scope;
//我们会在测试中使用这个scope

//模拟我们的Application模块并注入我们自己的依赖
 beforeEach(angular.mock.module('Application'));

//模拟Controller,并且包含 $rootScope 和 $controller
 beforeEach(angular.mock.inject(function($rootScope, $controller){

//创建一个空的 scope
  scope = $rootScope.$new();

//声明 Controller并且注入已创建的空的 scope
  $controller('MainCtrl', {$scope: scope});
 });

// 测试从这里开始
});

从代码中你可以看到我们注入了我们自己的 scope,因此我们可以在它的外部验证它的信息。同时,别忘了模拟模块本身(第7行代码)!我们现在已经为测试做好了准备:

home.tests.js

// 测试从这里开始
it('should have variable text = "Hello World!"', function(){
 expect(scope.text).toBe('Hello World!);
});

如果你运行这个测试,它可以在任何指向Karma的浏览器中执行,并且测试通过。

发送$resource请求

现在我们已经准备好测试 $resource 请求。要完成这个请求,我们需要使用到 $httpBackend, 它一个模拟版本的Angular $http。我们会创建另一个叫做 $httpBackend 的变量,在第二个 beforEach块中,注入 _$httpBackend_ 并将新创建的变量指向 _$httpBackend_。接下来我们会告诉 $httpBackend 如何对请求做出响应。

$httpBackend = _$httpBackend_;
$httpBackend.when('GET', 'Users/users.json').respond([{id: 1, name: 'Bob'}, {id:2, name: 'Jane'}]);

我们的测试: home.tests.js

it('should fetch list of users', function(){
   $httpBackend.flush();
   expect(scope.users.length).toBe(2);
   expect(scope.users[0].name).toBe('Bob');
  });

都放到一起

home.tests.js

'use strict';

describe('MainCtrl', function(){
 var scope, $httpBackend;
//we'll use these in our tests

//mock Application to allow us to inject our own dependencies
 beforeEach(angular.mock.module('Application'));

//mock the controller for the same reason and include $rootScope and $controller
 beforeEach(angular.mock.inject(function($rootScope, $controller, _$httpBackend_){
  $httpBackend = _$httpBackend_;
  $httpBackend.when('GET', 'Users/users.json').respond([{id: 1, name: 'Bob'}, {id:2, name: 'Jane'}]);

//create an empty scope
  scope = $rootScope.$new();

//declare the controller and inject our empty scope
  $controller('MainCtrl', {$scope: scope});
 });

// tests start here
 it('should have variable text = "Hello World!"', function(){
  expect(scope.text).toBe('Hello World!');
 });
 it('should fetch list of users', function(){
  $httpBackend.flush();
  expect(scope.users.length).toBe(2);
  expect(scope.users[0].name).toBe('Bob');
 });
});

技巧

Karma会运行所有文件中的所有测试用例,如果你只想运行所有测试的一个子集,修改 describe 或 it 为 ddescribe 或 iit 来运行个别的一些测试。如果有些测试你不想运行他们,那么修改 describe 或 it 为 xdescribe 或 xit 来忽略这些代码。

你也可以在html文件的页面上运行你的测试。举例的代码如下:
home.runner.html

<!DOCTYPE html>
<html>
<head>
 <title>Partner Settings Test Suite</title>

<!-- include your script files (notice that the jasmine source files have been added to the project) -->
 <script type="text/javascript" src="../jasmine/jasmine-1.3.1/jasmine.js"></script>
 <script type="text/javascript" src="../jasmine/jasmine-1.3.1/jasmine-html.js"></script>
 <script type="text/javascript" src="../angular-mocks.js"></script>
 <script type="text/javascript" src="home.tests.js"></script>
 <link rel="stylesheet" href="../jasmine/jasmine-1.3.1/jasmine.css"/>
</head>
<body>

<!-- use Jasmine to run and display test results -->
 <script type="text/javascript">
  var jasmineEnv = jasmine.getEnv();
  jasmineEnv.addReporter(new jasmine.HtmlReporter());
  jasmineEnv.execute();
 </script>
</body>
</html>
(0)

相关推荐

  • 利用Jasmine对Angular进行单元测试的方法详解

    前言 本文主要介绍的是关于利用Jasmine对Angular单元测试的相关内容,以下是我假定那些极少或压根没写单元测试的人准备的,因此,会白话解释诸多概念性问题,同时会结合 Jasmine 与之对应的方法进行讲解. 一.概念 Test Suite 测试套件,哪怕一个简单的类,也会有若干的测试用例,因此将这些测试用例集合在一个分类下就叫Test Suite. 而在 Jasmine 就是使用 describe 全局函数来表示,它的第一个字符串参数用来表示Suite的名称或标题,第二个方法参数就是实现

  • 使用Jasmine和Karma对AngularJS页面程序进行测试

    AngularJS是继jQuery之后发生在JavaScript上最好的东西.这也是JavaScript开发一直以来想要的方式.Angular主要的优点之一就是它的依赖注入(Dependency Injection),它非常利于代码的单元测试.但有点小怪异的是,我在无论如何都没能找到一个介绍如何做单元测试的教程. 当然有很多不错的推荐:使用Jasmine测试框架和Karma测试执行器(Test Runner):但是并没有一篇完整的从无到有指导如何测试的教程.所以我写了这篇文章.我在网上找了很多资

  • AngularJs页面筛选标签小功能

    AngularJS 简介 AngularJS 是一个 JavaScript 框架.它可通过 <script> 标签添加到 HTML 页面. AngularJS 通过 指令 扩展了 HTML,且通过 表达式 绑定数据到 HTML. AngularJS 是一个 JavaScript 框架 AngularJS 是一个 JavaScript 框架.它是一个以 JavaScript 编写的库. AngularJS 是以一个 JavaScript 文件形式发布的,可通过 script 标签添加到网页中:

  • WebApi+Bootstrap+KnockoutJs打造单页面程序

    一.前言 在前一个专题快速介绍了KnockoutJs相关知识点,也写了一些简单例子,希望通过这些例子大家可以快速入门KnockoutJs.为了让大家可以清楚地看到KnockoutJs在实际项目中的应用,本专题将介绍如何使用WebApi+Bootstrap+KnockoutJs+Asp.net MVC来打造一个单页面Web程序.这种模式也是现在大多数公司实际项目中用到的. 二.SPA(单页面)好处 在介绍具体的实现之前,我觉得有必要详细介绍了SPA.SPA,即Single Page Web App

  • AngularJS页面带参跳转及参数解析操作示例

    本文实例讲述了AngularJS页面带参跳转及参数解析操作.分享给大家供大家参考,具体如下: 页面带参跳转 $scope.LoginSucessLocation = function () { var hre = 'http://ctb.qingguo.com/weixinCt/main#/upload_topic_start?uid=' + $scope.uid + '&orgcode=' + $scope.orgCode; location.href = hre; } 在url的后面,增加?

  • 利用webstrom调试Vue.js单页面程序的方法教程

    前言 使用 webstrom 调试 Vue.js 单页面程序,理论上来说应该是支持所有用 webpack 构建的应用程序 webstrom 版本:2017.1 代码:使用 vue-cli 构建的基础单页面应用 修改 webpack 配置 由于 webpack 把所有文件全部打包到一起,所以我们需要 webpack 提供给我们一个源地图 修改 devtool 为 source-map 这是我的开发配置文件 webpack.dev.conf.js module.exports = merge(bas

  • 使用Webpack构建多页面程序的实现步骤

    使用webpack搭建单页面程序十分常见,但在实际开发中我们可能还会有开发多页面程序的需求,因此我研究了一下如何使用webpack搭建多页面程序. 原理 将每个页面所在的文件夹都看作是一个单独的单页面程序目录,配置多个entry以及html-webpack-plugin即可实现多页面打包. 下面为本项目目录结构 . ├─ src │ └─ pages │ ├─ about │ │ ├─ index.css │ │ ├─ index.html │ │ └─ index.js │ └─ index

  • angularjs中的e2e测试实例

    在上一篇文章里有讲到ng的单元测试,今天来说说e2e(端对端)测试. 当我们测试某个模块的单个功能点时,单元测试最适合,不过当面临用户进行多个页面交互的时候产生bug了,单元测试就不行了,这时候就得用e2e来模拟用户操作还原问题现场.当然利用e2e测试也能够测试程序的健壮性,很多单元测试办不到的事情,e2e测试都能够办到. 之前,ng是利用Angular Scenario Runner来运行e2e测试,现在已经换成Protractor来跑e2e了. Protractor Protractor是A

  • AngularJS页面传参的5种方式

    Angular页面传参有多种办法,根据不同用例,我举5种最常见的(请在网页版知乎浏览答案): 1. 基于ui-router的页面跳转传参 (1) 在AngularJS的app.js中用ui-router定义路由,比如现在有两个页面,一个页面(producers.html)放置了多个producers,点击其中一个目标,页面跳转到对应的producer页,同时将producerId这个参数传过去. .state('producers', { url: '/producers', templateU

  • angularjs 页面自适应高度的方法

    需求 在angularjs构建的业务系统中,通过ui-view路由实现页面跳转,初始化进入系统后,右侧内容区域需要自适应浏览器高度. 实现方案 在ui-view所在的Div添加directive,directive中通过element.css初始化计算div的高度,动态更新div高度 directive监听($$watch)angular的$digest,实时获取body高度,动态赋值model或element.css改变 方案1:添加directive和element.css自适应高度 1.创

  • AngularJS页面访问时出现页面闪烁问题的解决

    我们知道在应用的页面或者组件需要加载数据时,浏览器和angular渲染页面都需要消耗一定的时间.这里的间隔可能很小,甚至让人感觉不到区别:但也可能很长,这样会导致让我们的用户看到了没有被渲染过的页面. 这种情况被叫做Flash Of Unrendered Content (FOUC)(K)?and is always unwanted.下面我们将要介绍几个不同的方式防止这种情况发生在我们的用户身上. 1.ng-cloak ng-cloak指令是angular的内置指令,它的作用是隐藏所有被它包含

随机推荐