测试应用

1.测试路由
我们需要检测路由是否在运作,是否找到了,或者是404了。我们要确认路由事件触发了,预期的模板是否真的加载了。既然路由会改变页面的地址(URL)和页面内容,我们需要检测路由是否被加载了,页面是否找到了,在这中间发生了什么。
一段简单的路由代码:
angular.module('myApp', ['ngRoute'])
.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'HomeController'})
.when('/login', {
templateUrl: 'views/login.html',
controller: 'LoginController'})
.otherwise({redirectTo '/'});
})
测试路由我们需要做以下几件事:
(1)注入$route、$location和$rootScope服务。
(2)建立一个模拟的后端来处理XHR,获取模板代码。
(3)设置一个地址,运行一个$digest生命周期
Step1:在测试中引用服务,并设置一个模拟后端,从templateUrl获取模板。可以用$httpBackend来创建断言来判断指定模板被加载了.
describe('Routes test', function() {
// 在测试中模拟模块
beforeEach(module('myApp'));
var location, route, rootScope;
beforeEach(inject(
function(_$location_, _$route_, _$rootScope_) {
location = _$location_;
route = _$route_;
rootScope = _$rootScope_;
}));
describe('index route', function() {
beforeEach(inject(
function($httpBackend) {
$httpBackend.expectGET('views/home.html')
.respond(200, 'main HTML');
}));
// 我们的测试代码放在这里
});
});
Step2:
为了用单元测试来测试路由,我们需要模拟路由在生产中的运作。路由借助于digest生命周期来运行,当location被设置以后,它使用一个
digest循环周期来处理路由,改变页面内容,然后结束本次路由。了解了这些之后,我们就需要解释测试中路径的变更。
在测试中,我们打算在应用的index路由上测试两个状态:当用户导航到首页时,指定的控制器会给他们显示首页;当用户导航到一个未知路由时,他们会按照在otherwise函数中定义的那样被带到首页。
我们可以通过建立$location服务来传递路径的方式测试这些条件。为了触发location请求,我们要运行一个digest周期(在$rootScope上),然后检测控制器是符合预期的(在本例中,是“HomeController”)。
it('should load the index page on successful load of /',
function() {
location.path('/');
rootScope.$digest(); // 调用digest循环
expect(route.current.controller)
.toBe('HomeController')
});
it('should redirect to the index path on non-existent
route', function() {
location.path('/definitely/not/a/_route');
rootScope.$digest();
expect(route.current.controller)
.toBe('HomeController')
});
2.测试控制器
在建立单元测试的过程中,需要确保:
建立了测试来模拟模块;
用一个已知的作用域实例来存储控制器的一个实例;
基于作用域来测试我们的预期。
要初始化一个控制器实例,需要使用$new()方法从$rootScope创建某作用域的一个新实例。这个新实例会建立Angular在运行时使用的作用域继承。有了这个作用域,就可以初始化一个新的控制器,把这个作用域作为控制器的$scope传递过去。
describe('Unit controllers: ', function(){
// 模拟myApp模块
beforeEach(module('myApp'));
describe('FrameController', function() {
// 局部变量
var FrameController, scope;
beforeEach(inject(
function($controller, $rootScope) {
// 创建子作用域
scope = $rootScope.$new();
// 创建FrameController的新实例
FrameController = $controller('FrameController',
{ $scope: scope });
}));
// 我们的测试代码放在这里
});
});
在FrameController里,我们有一个时钟在应用顶部显示当前时间。我们也可以访问一个用户和他的时区。具体的控制器的代码如下
angular.module('myApp.controllers', [])
.controller('FrameController',
function($scope, $timeout) {
$scope.time = {
today: new Date()
};
$scope.user = {
timezone: 'US/Pacific'
}
var updateClock = function() {
$scope.time.today = new Date();
};
var tick = function() {
$timeout(function() {
$scope.$apply(updateClock);
tick();
}, 1000);
}
tick();
});
我们要测试控制器的两个功能:时间已被定义;用户已被定义,并且有时区。
it('should have today set', function() {
expect(scope.time.today).toBeDefined();
});
it('should have a user set', function() {
expect(scope.user).toBeDefined();
});
再举个简单易懂的例子:
//创建一个scope对象,true表示它不会继承父级的变量,以免带来困扰
var scope=$rootScope.$new(true);
//找到SomeController,并对scope进行初始化
$controller('$SomeController',{$scope:scope});  //在这里也可以注入其他被mock的service或resolve的对象
//期待scope上应该出现一个name属性,其值为some one
$expect(scope.name).toEqual('some one');
//期待scope上应该出现一个greeting函数,调用它后的值为hello,some one
$expect(scope.greeting()).toEqual('hello,some one');
3.测试工厂和服务
Service可以是函数,可以是类,也可以是变量,所以测试起来没什么固定的形式,但是步骤和原理是相似的。
注入这个Service,把它保存为一个变量;
如果是函数,就调用它;如果是类,就new它,然后检查成员;如果是变量,就对比它的值。
var myClass;
//注入
beforeEach(inject(function(_MyClass_){
     MyClass=_MyClass_;   //赋给外部变量,以便后面的测试中使用
}));
it('someMethod should be 2',function(){
     var obj=new MyClass();
     expect(obj.someMethod()).toEqual(2);
});
4.测试过滤器
首先,要访问过滤器,只需简单地把$filter服务注入到我们的测试中。这样我们就得到了一个在此过程中查找过滤器的途径:
describe('Unit: Filter tests', function() {
var filter;
// 在测试中模拟我们的引用
beforeEach(module('myApp'));
beforeEach(inject(function($filter) {
filter = $filter;
}));
});
有了对控制器的访问,在过滤器的输出上设置预期就是很容易的事了。
it('should give us two decimal points',
function() {
expect(filter('number')(123, 2)).toEqual('123.00');
});
5.测试模板
测试模板时,我们着重于确保:特定的内容模板被加载了,模板中特定的数据也在视图中显示了。
可以建立一个断言:模板正常加载了。要做到这个,需要建立测试来期望对主页模板的一个请求,并且执行一个视图的变更来验证它是不是真的加载了。
describe('Unit: Templates', function() {
var $httpBackend,
location,
route,
rootScope;
beforeEach(module('myApp'));
beforeEach(inject(
function(_$rootScope_, _$route_, _$httpBackend_, _$location_){
location = _$location_;
rootScope = _$rootScope_;
route = _$route_;
$httpBackend = _$httpBackend_;
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
// 我们的测试代码放在这里
});
现在,可以建立测试来反映导航到应用不同部分时的预期。
it('loads the home template at /', function() {
$httpBackend.expectGET('templates/home.html')
.respond(200);
location.path('/');
rootScope.$digest(); // 调用digest循环
$httpBackend.flush();
});
it('loads the dashboard template at /dashboard', function() {
$httpBackend.expectGET('templates/dashboard.html')
.respond(200);
location.path('/dashboard');
rootScope.$digest(); // 调用digest循环
$httpBackend.flush();
});
注意,我们并未在测试中返回一个模板(是.respond(200),而不是.respond(200, "\<div\>\</div\>"))。鉴于我们只是在验证模板是否在请求中加载了,没有必要担心到底显示了什么。
6.测试事件
当对事件的触发进行单元测试时,我们感兴趣的是它们究竟调用了什么,还有是否真的调用了正确的事件。其次,我们主要关心处理程序有它们需要的数据。
使用Jasmine的辅助方法spnOn()可以非常容易地建立事件测试。设想我们在测试一个控制器,它触发了一个$emit函数。基于这个函数,我们可以建立一个预期:事件被触发了,并且用我们所感兴趣的任意参数调用了。
describe('myApp', function() {
var scope;
beforeEach(angular.mock.module('myApp'));
beforeEach(angular.mock.inject(function($rootScope) {
scope = $rootScope.$new();
});
});
测试建好之后,就可以简单地在作用域上为$emit或者$broadcase事件设置一个spyOn()调用了。

// ...
});
it('should have emit called', function() {
spyOn(scope, "$emit");
scope.closePanel(); // 示例
// 或者任意可能导致emit被调用的事件
expect(scope.$emit)
.toHaveBeenCalledWith("panel:closed",
panel.id);
});
我们也可以测试事件:设置一个事件触发后调用的$on()监听器。要执行$broadcast方法,
可以简单地在作用域上调用$broadcast,并且对事件将会导致的作用域变化建立一个预期。
// ...
it('should set the panel to closed state',
function() {
scope.$broadcast("panel:closed", 1);
expect(scope.panel.state).toEqual("closed");
});

AngularJS测试二 jasmine测试路由 控制器 过滤器 事件 服务的更多相关文章

  1. 【转】学习使用Jmeter做压力测试(二)--压力测试的实施

    JMeter测试步骤: 1.建立测试计划 2.添加线程组 3.添加HTTP请求 4.增加监听器 5.执行测试计划 6.根据JMeter提供的报告分析结果 一.目标 测试访问目标服务器网站首页的每秒查询 ...

  2. angularJS(二):作用域$scope、控制器、过滤器

    app.controller创建控制器 一.作用域 Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带. Scope 是一个对象,有可用的方法和属性. ...

  3. 用Karma和Jasmine测试Angular应用

    TEST: Before you've written any of the code, you know how you want it to behave. You have a specific ...

  4. Android APP压力测试(二)之Monkey信息自动收集脚本

      Android APP压力测试(二) 之Monkey信息自动收集脚本 前言: 上一篇Monkey介绍基本搬抄官方介绍,主要是为了自己查阅方便.本文重点介绍我在进行Monkey时如何自动收集相关信息 ...

  5. angular测试-Karma + Jasmine配置

    首先讲一下大致的流程: 需要node环境,首先先要安装node,node不会?请自行搜索.版本>0.8 安装node完成之后先要测试下npm是否测试通过,如下图所示 首先看下目录结构 目录为:F ...

  6. 总结Selenium自动化测试方法(二)测试环境搭建

    (接上期内容) 二.测试环境搭建 1.安装python 现在python3.0比python2.0多了一些改进的功能(详见http://zhidao.baidu.com/link?url=3sT1g7 ...

  7. 大数据项目测试<二>项目的测试工作

    大数据的测试工作: 1.模块的单独测试 2.模块间的联调测试 3.系统的性能测试:内存泄露.磁盘占用.计算效率 4.数据验证(核心) 下面对各个模块的测试工作进行单独讲解. 0. 功能测试 1. 性能 ...

  8. 数据驱动测试二:使用TestNG和CSV文件进行数据驱动

    转载:https://blog.csdn.net/heart_1014/article/details/52013173 使用@DataProvider注解定义当前方法中的返回对象CSV文件(存放测试 ...

  9. stm32+lwip(二):UDP测试

    我是卓波,很高兴你来看我的博客. 系列文章: stm32+lwip(一):使用STM32CubeMX生成项目 stm32+lwip(二):UDP测试 stm32+lwip(三):TCP测试 stm32 ...

随机推荐

  1. .net版ckeditor配置水印功能(转)

    本文简单讲解ckfinder控件给上图片加水印效果. 1.将ckfinder/plugins/watermark/bin/Debug目录下的CKFinder_Watermark.dll和CKFinde ...

  2. angular.js 数字

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...

  3. css布局小技巧 2016.03.06

    偶遇一个可爱的css布局学习网站,立刻学起来哟- max-width: 当页面左右宽度缩小时,为了避免出现左右滚动条的糟糕体验,就可以用到max-width啦!页面比宽度小时,会自动缩小哦- max- ...

  4. Java设计模式(学习整理)----装饰模式

    1.概念: (在我看来,模式就像是是一种思想,在这种思想的指引下,对代码和结构的一番加工和整合而已!都是套路!) 装饰模式又称包装(Wrapper)模式,是以对客户端透明的方式扩展对象的功能,是继承关 ...

  5. TestNG扩展

    1. TestNG API 本章节将讨论如何使用TestNG API来创建自己的TestNG对象.TestNG的API基本由接口组成,这样做是为了容易模拟TestNG返回的对象. 1.1 org.te ...

  6. [转载]python os.path模块

    os.path模块主要用于文件的属性获取,在编程中经常用到,以下是该模块的几种常用方法.更多的方法可以去查看官方文档:http://docs.python.org/library/os.path.ht ...

  7. dedecms设置文章分页后,标题会带有序号的解决方法

    至于删除分页后标题后面的序号,找到include/arc.archives.class.php 打开,找到 if($i>1) $this->Fields['title'] = $this- ...

  8. 通过命令修改wampserver的mysql密码

    WAMP安装好后,mysql教程密码是为空的,那么要如何修改呢?其实很简单,通过几条指令就行了,下面我就一步步来操作. 首先,通过WAMP打开mysql控制台. 提示输入密码,因为现在是空,所以直接按 ...

  9. Python核心编程2第六章课后练习

    6-1 字符串 .string 模块中是否有一种字符串方法或者函数可以帮我鉴定一下一个字符串是否是另一个大字符串的一部分? #!/usr/bin/env python def contain(str1 ...

  10. JS:window.onload的使用介绍

    作者: 字体:[增加 减小] 类型:转载 时间:2013-11-13我要评论 window.onload在某些情况下还是比较实用的,比如加载时执行哪些脚本等等,下面有几个不错的示例,需要的朋友可以参考 ...