更新 2018-06-03

spy object

当组件或则服务有对其它服务依赖的时候,我们通常会把这些依赖写成 spy 或则叫 fake.

为什么这样做的呢 ?

主要的原因是我们不应该依赖具体的代码,假设具体的代码错了,我们这个服务也会跟着报错.

所以单元测试的 "单元",就是说我们必须把我们要测试的东西独立放到一个测试环境里头,对外部任何依赖都做隔离.

如果报错,那么一定是它错了,绝对不能是因为被其它人影响而报错. 所以我们必须把依赖的服务都写成 spy.

describe('SecondService', () => {

  let firstServiceSpy: jasmine.SpyObj<FirstService>; // 定义依赖的服务

  beforeEach(() => {
firstServiceSpy = jasmine.createSpyObj('firstService', ['getValue']); //创建假的服务
firstServiceSpy.getValue.and.returnValue('firstValue'); // 直接设定返回的结果 (这样不管这个服务的具体实现正不正确, 我们都不会被影响到)
TestBed.configureTestingModule({
providers: [
SecondService,
{ provide: FirstService, useValue: firstServiceSpy } // 替换掉 provide 就可以了
]
});
}); it(`getValue should return 'firstValueSecondValue'`, inject([SecondService], (secondService : SecondService) => {
expect(secondService.getValue()).toBe('firstValuesecondValue');
})); });

第一次写单元测试.

以前一直都有听说 TDD 的事情.

今天总算是去尝试了一下.

先说说 TDD 的想法, 是这样的,

开发项目的流程 : 确定需求 -> 写类,接口,方法的名字(不写具体实现代码哦) -> 写测试代码 -> 这时测试的话一定是全部 fail 因为实现代码还没写嘛 -> 写实现代码 -> 运行测试 ...

这样的流程适合需要敏捷开发的项目, 如果你的项目经常需要扩展, 而且扩展往往是不在预计范围内的, 那么你必然需要使用敏捷开发模式和流程.

也只有把测试写好,以后代码修改了以后才不需要人工的再去测试一遍.

倒过来看的话,如果你的项目逻辑简单,扩展总是在预计范围呢, 那么你硬去搞敏捷开发写测试代码的话,就有点浪费了.

angular 框架支持测试. 使用 karma , jasmine, cli 来跑。

个人觉得要写的好测试, 对 angular 的依赖注入机制要有点基础.

通常我们会测试的东西是 component 和 service.

记得不是所以的东西都要测试的,就好像数学考试一样, 不需要每一题都 double check, 只测试那些容易出错的地方就可以了.

那什么地方容易出错呢. 这个因人而异, 看你自己的经验.

我个人的建议是测试那些关系比较多和复杂的地方.

比如我们要测试 component

我们需要先把 component 的依赖准备好,比如 component 依赖的服务.

beforeEach(() => {
TestBed.configureTestingModule({
imports: [StoogesModule],
declarations: [
SimpleComponent
],
providers: [
MockBackend,
BaseRequestOptions
]
});
TestBed.overrideComponent(SimpleComponent, {
set: {
providers: [
{
provide: Http,
deps: [
MockBackend,
BaseRequestOptions
],
useFactory: (backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
}
]
}
});
TestBed.compileComponents();
this.fixture = TestBed.createComponent(SimpleComponent);
this.com = this.fixture.debugElement.componentInstance;
});

TestBed.configureTestingModule 是让我们写准备环境的. 它和 NgModule 差不多.

MockBackend 是模拟 http 数据用的

TestBed.overrideComponent 这个方法用来覆盖组件定义好的 provider

it("test", async(inject([MockBackend], (backend: MockBackend) => {
const mockResponse = {
data: [
{ id: 0, name: 'Video 0' },
{ id: 1, name: 'Video 1' },
{ id: 2, name: 'Video 2' },
{ id: 3, name: 'Video 3' },
]
}; backend.connections.subscribe((connection) => {
console.log("test");
connection.mockRespond(new Response(new ResponseOptions({
body: JSON.stringify(mockResponse)
})));
}); let com = this.com as SimpleComponent;
com.dada().subscribe(v => {
expect("haha").toBe("haha");
});
})));

async() 是帮助我们写异步的, 放在 It 的方法里面就行了

inject() 自然是依赖注入 service 咯, 这个写法是不是让你想起了 ng1 ?

backend.connections 是拦截所有的请求, 我们进一步判断 connection request url 来做出不同的 response data.

可以看出来,主要的代码都是为了搭建环境. 通过依赖注入去覆盖原有的 provider.

我们在看看 service.spec.ts

describe("test", () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
SimpleService
]
});
}); it("test1", async(inject([SimpleService], async (simple: SimpleService) => {
let data = await simple.getData();
console.log("a");
expect(data).toBe("a");
})));
});

这个比较简单, 因为不用 create component and override component provider.

写 await async 也是 ok 的哦.

angular2 学习笔记 ( unit test 单元测试 )的更多相关文章

  1. Angular2学习笔记(1)

    Angular2学习笔记(1) 1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之 ...

  2. angular2 学习笔记 ( rxjs 流 )

    RxJS 博大精深,看了好几篇文章都没有明白. 范围牵扯到了函数响应式开发去了... 我对函数式一知半解, 响应式更是第一次听到... 唉...不过日子还是得过...混着过先呗 我目前所理解的很浅,  ...

  3. angular2 学习笔记 ( ngModule 模块 )

    2016-08-25, 当前版本是 RC 5. 参考 : https://angular.cn/docs/ts/latest/guide/ngmodule.html 提醒 : 这系列笔记的 " ...

  4. Scala学习笔记——断言和单元测试

    1.断言 assert(conditon)将在条件不成立的时候,抛出assertionError assert(conditon,explanation)讲在条件不成立的时候,抛出explanatio ...

  5. Angular2学习笔记(1)——Hello World

    1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之前主要使用的是jQuery,由于 ...

  6. Angular2学习笔记——路由器模型(Router)

    Angular2以组件化的视角来看待web应用,使用Angular2开发的web应用,就是一棵组件树.组件大致分为两类:一类是如list.table这种通放之四海而皆准的通用组件,一类是专为业务开发的 ...

  7. Angular2学习笔记——Observable

    Reactive Extensions for Javascript 诞生于几年前,随着angular2正式版的发布,它将会被更多开发者所认知.RxJs提供的核心是Observable对象,它是一个使 ...

  8. Angular2学习笔记——在子组件中拿到路由参数

    工作中碰到的问题,特此记录一下. Angular2中允许我们以`path\:id\childPath`的形式来定义路由,比如: export const appRoutes: RouterConfig ...

  9. Angular2学习笔记——NgModule

    在Angular2中一个Module指的是使用@NgModule修饰的class.@NgModule利用一个元数据对象来告诉Angular如何去编译和运行代码.一个模块内部可以包含组件.指令.管道,并 ...

随机推荐

  1. php文件上传原理详解(含源码)

    1.文件上传原理 将客户端的文件上传到服务器,再将服务器的临时文件上传到指定目录 2.客户端配置 提交表单 表单的发送方式为post 添加enctype="multipart/form-da ...

  2. hadoop2.x源码编译

    转载请标明出处: http://blog.csdn.net/zwto1/article/details/50733753: 介绍 本篇主要会涉及以下内容: 学会编译hadoop2.x源码 编译hado ...

  3. PAT乙级-1047. 编程团体赛(20)

    编程团体赛的规则为:每个参赛队由若干队员组成:所有队员独立比赛:参赛队的成绩为所有队员的成绩和:成绩最高的队获胜. 现给定所有队员的比赛成绩,请你编写程序找出冠军队. 输入格式: 输入第一行给出一个正 ...

  4. 【Unity与23种设计模式】解释器模式(Interpreter)

    GoF中定义: "定义一个程序设计语言所需要的语句,并提供解释来解析(执行)该语言." 传统上,执行程序代码通常通过两种方式 第一种:编译程序 第二种:解释器 常见的使用解释器的程 ...

  5. Nginx配置ThinkPHP下的url重写(隐藏入口)

    搭建好项目后,在网址上输入域名,只能访问首页,其他页面全是404. 在域名后面和控制器前面加上index.php就可以访问. 在tp5官网手册查找后进行配置修改. 打开nginx.conf 后 ,在s ...

  6. 如何 创建一个model对象保存到LIST集合里面并取出来

    /// <summary> /// 缓存客服集合信息 /// </summary> public class model { /// <summary> /// 客 ...

  7. 智能合约语言 Solidity 教程系列1 - 类型介绍

    现在的Solidity中文文档,要么翻译的太烂,要么太旧,决定重新翻译下.尤其点名批评极客学院名为<Solidity官方文档中文版>的翻译,机器翻译的都比它好,大家还是别看了. 写在前面 ...

  8. UWP 圆形菜单

    用过Surface dial的童鞋们都很熟悉,当使用Dial的时候,那个圆形菜单很漂亮,那么我们在普通的uwp中是否也可以实现吗? 答案是肯定的. 其实这是来源于GayHub的一个开源项目,做的很不错 ...

  9. MySQL——delete 和 truncate 以及 drop 区别

    delete 和 truncate 以及 drop 区别 (个人理解,如有错误,请指出) delete < truncate < drop 删除方式: truncate  只删除数据.逐条 ...

  10. 【深度学习】用PaddlePaddle进行车牌识别(二)

    上节我们讲了第一部分,如何用生成简易的车牌,这节课中我们会用PaddlePaddle来识别生成的车牌. 数据读取 在上一节生成车牌时,我们可以分别生成训练数据和测试数据,方法如下(完整代码在这里): ...