美文网首页react & vue & angularAngular
Angular 单元测试实践 (4)

Angular 单元测试实践 (4)

作者: 品品下午茶 | 来源:发表于2022-06-05 06:45 被阅读0次

    本文继续介绍如何对 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: `<h2 highlight="skyblue">国学</h2>
      <h3>今日经典:</h3>
      <q>学而时习之,不亦乐乎。</q>`
    })
    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 <h2>', () => {
        const bgColor = container.style.backgroundColor;
        expect(bgColor).toBe('skyblue’);
      });
    

    测试报表页面:

    指令测试报表页面

    测试表单

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

    <form [formGroup]="searchForm" (ngSubmit)="search()”>
      <input type="text" placeholder="请输入用户名" formControlName=“searchText”>
      <button type="submit" [disabled]="searchForm.invalid">查询</button>
    </form>
    

    组件类定义如下:

    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<SearchComponent>;
    
      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 方法,对输出到控制台到内容进行验证。

    测试报表页面:

    表单测试报表页面

    相关文章

      网友评论

        本文标题:Angular 单元测试实践 (4)

        本文链接:https://www.haomeiwen.com/subject/iwncmrtx.html