Angular 单元测试实践 (3)

对 Angular 服务的单元测试,可以分为三类:

  1. 测试同步操作
  2. 测试异步操作
  3. 测试服务依赖

在测试服务前,我们先创建一个服务,实现对一个数组数据的检索和添加:

import { Injectable } from '@angular/core’;
import { Observable, of } from ‘rxjs’;
import { delay } from 'rxjs/operators’;

const books = ['《图书 壹》', '《图书 贰》', '《图书 叁》', '《图书 肆》', '《图书 伍》’];

@Injectable({
  providedIn: ‘root’
})
export class AsyncService {

  constructor() { }

  getData(): Observable<string[]> {
    return of(books).pipe(delay(500));
  }

  setData(name: string) {
    return [...books, name ];
  }
}

测试同步操作

测试服务的同步操作,是比较简单的,例如,测试一个返回简单数组数据的方法。

  it('should set data', () => {
    const result = service.setData('《图书 零》’);
    expect(result.length).toBe(6);
  });

在测试用例中,直接调用 setData 方法,并检查结果:如果集合的长度增加了 1,则表示测试通过。

测试异步操作

在对异步操作进行测试时,需要订阅 getData 方法,在方法执行完成后,再对结果进行检查验证。

  it('should get data', (done: DoneFn) => {
    service.getData().subscribe(books => {
      expect(books.length).toBe(5);
      done();
    });
  });

因为 Karma 不知道异步操作何时执行完成,需要使用 done 方法通知测试框架,表明异步操作已完成,可以进行结果验证。

测试服务依赖

在一个服务的业务逻辑中,经常会包含访问远程 API 的情况,那么该如何测试这样的服务呢?

在下面的这个服务中,包含了 getBooksaddBook 两个方法,均调用了远程的 API 服务,都需要依赖 HttpClient 完成网络请求。

import { Injectable } from '@angular/core’;
import { HttpClient } from "@angular/common/http”;
import { Observable } from ‘rxjs’;

@Injectable({
  providedIn: ‘root’
})
export class DataService {

  constructor(private http: HttpClient) { }

  getBooks(): Observable<string[]> {
    return this.http.get<string[]>('api/books’);
  }

  addBook(name: string) {
    return this.http.post<string>('api/books', {book: name});
  }
}
  1. 我们先来测试 getBooks 方法:
  it('should get books', () => {
    const books = ['图书 零', '图书 陆’];
    service.getBooks().subscribe(books => expect(books.length).toBe(2));
    const req = httpTestingController.expectOne('api/books’);
    expect(req.request.method).toEqual('GET’);
    req.flush(books);
  });

HttpTestingController 类提供了 expectOne 方法,接受一个网络地址参数(URL)。expectOne 方法会创建一个模拟的请求对象,并确保请求只发一次。

  1. 再对 addBook 方法进行测试:
    service.addBook('《球状闪电》').subscribe();
    const req = httpTestingController.expectOne('api/books’);
    expect(req.request.method).toEqual('POST’);
    expect(req.request.body).toEqual({book: '《球状闪电》’})
    req.flush(‘’);
  });

因为添加操作使用的是 POST 方法,需要验证请求体包含了合适的数据。

测试报表页面

服务测试报表页面
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容