Angular 单元测试实践 (4)

本文继续介绍如何对 Angular 的管道(pipe)、指令(directive)和表单(form)进行单元测试。

测试管道

Angular 的指令是一个实现了 PipeTransform 接口的 TypeScript 类,暴露了 transform 方法。指令操作通常是同步的,很少与 DOM 元素进行交互,也几乎没有什么依赖。因此,对指令的单元测试也比较简单,甚至不需要 Angular 的测试工具类。

考虑这样一个管道 CommaSeperatorPipe:把逗号分割的字符串转换成一个列表:

import { Pipe, PipeTransform } from '@angular/core’;

@Pipe({
  name: ‘commaSeperator’
})
export class CommaSeperatorPipe implements PipeTransform {

  transform(value: string): string[] {
    return value.split(',’);
  }

}

测试代码只需要实例化一个管道对象,向 transform 方法传入一些模拟的数据,验证该方法转换的结果即可:

import { CommaSeperatorPipe } from './comma-seperator.pipe’;

describe('CommaSeperatorPipe', () => {
  it('create an instance', () => {
    const pipe = new CommaSeperatorPipe();
    expect(pipe).toBeTruthy();
  });

  it('should return an array', () => {
    const pipe = new CommaSeperatorPipe();
    expect(pipe.transform('1,2,3,4,5')).toEqual(['1', '2', '3', '4', '5’]);
  });
});

测试报表页面:

管道测试报表页面

测试指令

指令通常用来改变一个元素、组件或另一个指令的行为。指令一般和组件一起协同工作,没有外部的依赖。

考虑这样一个指令 HighlightDirective :基于绑定的数据值,设置元素的背景颜色:

import { Directive, ElementRef, Input, OnChanges } from '@angular/core’;

@Directive({ selector: '[highlight]’ })
/**
 * 设置宿主元素的背景颜色
 */
export class HighlightDirective implements OnChanges {

  defaultColor =  'rgb(211, 211, 211)'; // 默认为浅灰色

  @Input('highlight') bgColor = ‘’;

  constructor(private el: ElementRef) {
    el.nativeElement.style.customProperty = true;
  }

  ngOnChanges() {
    this.el.nativeElement.style.backgroundColor = this.bgColor || this.defaultColor;
  }
}

在下面 TestHost 这个组件里,测试 HighlightDirective 指令:

@Component({
  template: `

国学

今日经典:

学而时习之,不亦乐乎。` }) class TestHostComponent {}

现在就可以写单元测试,验证 h2 元素是否添加了 highlight 指令,并设置了正确的背景颜色。

describe('HighlightDirective', () => {
  let container: HTMLElement;

  beforeEach(() => {
    const fixture = TestBed.configureTestingModule({
      declarations: [ TestHostComponent, HighlightDirective ]
    })
    .createComponent(TestHostComponent);
    fixture.detectChanges();
    container = fixture.nativeElement.querySelector('h2’);
  });

  it('should have skyblue 

', () => { const bgColor = container.style.backgroundColor; expect(bgColor).toBe('skyblue’); });

测试报表页面:

指令测试报表页面

测试表单

表单是 Angular 应用的重要组成部分,很少有应用不包含一个表单的。我们使用下面的查询表单,介绍如何对表单进行单元测试。

组件类定义如下:

import { Component, OnInit } from '@angular/core’;
import { FormControl, FormGroup, Validators } from '@angular/forms’;

@Component({
  selector: 'app-search’,
  templateUrl: './search.component.html’,
  styleUrls: ['./search.component.css’]
})
export class SearchComponent implements OnInit {

  get searchText(): FormControl {
    return this.searchForm.controls.searchText as FormControl;
  }

  searchForm = new FormGroup({
    searchText: new FormControl('', Validators.required)
  });

  search() {
    if(this.searchForm.valid) {
      console.log(‘查询内容是: ' + this.searchText.value)
    }
  }
  constructor() { }

  ngOnInit(): void {
  }

}

这里,我们要测试三个地方:

  1. searchText 属性的设置是否正确
  2. 查询 按钮禁用状态是否正确
  3. console.log 是否调用正确

编写测试用例如下:

describe('SearchComponent', () => {
  let component: SearchComponent;
  let button: HTMLButtonElement;
  let fixture: ComponentFixture;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ SearchComponent ],
      imports: [ReactiveFormsModule]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(SearchComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    button = fixture.nativeElement.querySelector('button’);
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should set the searchText', () => {
    const input: HTMLInputElement = fixture.nativeElement.querySelector('input’);
    input.value = ‘Angular’;
    input.dispatchEvent(newEvent('input’));
    expect(component.searchText.value).toBe('Angular’);
  });

  it('should disable search button', () => {
    component.searchText.setValue(‘’);
    expect(button.disabled).toBeTrue();
  });

  it('should log to the console', () => {
    const spy = spyOn(console, 'log’);
    component.searchText.setValue('Angular’);
    fixture.detectChanges();
    button.click();
    expect(spy.calls.first().args[0]).toBe('查询内容是: Angular’);
  });
});

在第一个测试用例中,使用 nativeElement 属性的 querySelector 方法,定位到 input
元素,并设置该元素的值为 Angular. 接着,调用 input 元素的 dispatchEvent 方法,通知 Angular 框架,input 元素的值已经发生变化。最后,验证组件类的 searchText 属性值是否接收到了 input 元素的值。

在第二个测试用例中,首先,设置 input 元素的值为空。然后,验证查询按钮处于禁用状态。

在第三个测试用例中,首先,设置 input 元素的值为 Angular。然后,触发变化通知。接着,模拟按钮点击操作。最后,使用 Spying 方法,对输出到控制台到内容进行验证。

测试报表页面:

表单测试报表页面

版权声明:
作者:Mr李
链接:https://www.techfm.club/p/44501.html
来源:TechFM
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>