Angular2如何对自定义验证器指令进行单元测试?

Posted

技术标签:

【中文标题】Angular2如何对自定义验证器指令进行单元测试?【英文标题】:Angular2 how to unit test a custom validator directive? 【发布时间】:2017-02-18 20:19:43 【问题描述】:

我为输入字段编写了一个非常简单的自定义验证器:

import  Directive  from '@angular/core';
import  AbstractControl, NG_VALIDATORS  from '@angular/forms';

function numberValidator(c: AbstractControl) 
    if (!c.value) return null;
    return new RegExp('^[1-9][0-9]6,9$').test(c.value) ? null : 
        validateNumber: 
            valid: false
        
    


@Directive(
    selector: '[number-validator]',
    providers: [
         provide: NG_VALIDATORS, multi: true, useValue: numberValidator 
    ]
)
export class NumberValidator 

我想对这个验证器进行单元测试。我在 Angular2 页面上阅读了Test an attribute directive,但没有 css 或 html 发生变化。如何对这个验证器进行单元测试?

【问题讨论】:

【参考方案1】:

如果你想用简单的方法(我会这样做,因为所有逻辑都在验证器函数中),只是测试验证器函数。只需将控件传递给它

expect(numberValidator(new FormControl('123456'))).toEqual(
  'validateNumber':  'valid': false 
);
expect(numberValidator(new FormControl('123456789'))).toEqual(null);

如果你真的想在“被使用”时测试它,那么它会变得有点乏味。这些通常是我采取的步骤

    创建虚拟组件以使用指令 设置测试台配置 创建要测试的组件。 获取本机输入元素并向其分派无效输入事件 获取持有NgForm的注射器 检查表单是否失败 输入一个有效的输入并检查它是否通过。

与仅测试验证器方法相比,这要多得多。但无论如何它都在这里 ;-) 享受吧!

import  Component, Directive  from '@angular/core';
import  TestBed, async  from '@angular/core/testing';
import  dispatchEvent  from '@angular/platform-browser/testing/browser_util';
import  By  from '@angular/platform-browser';
import  FormsModule, NG_VALIDATORS, AbstractControl,
         NgForm, FormControl  from '@angular/forms';

function numberValidator(c: AbstractControl) 
  if (!c.value) return null;
  return new RegExp('^[1-9][0-9]6,9$').test(c.value) ? null : 
    validateNumber: 
      valid: false
    
  ;


@Directive(
  selector: '[number-validator]',
  providers: [
     provide: NG_VALIDATORS, multi: true, useValue: numberValidator 
  ]
)
export class NumberValidator 


@Component(
  template: `
    <form>
      <input name="number" type="text" ngModel number-validator />
    </form>
  `
)
class TestComponent 


describe('component: TestComponent', () => 
  beforeEach(() => 
    TestBed.configureTestingModule(
      imports: [ FormsModule ],
      declarations: [TestComponent, NumberValidator]
    );
  );

  it('should validate (easy)', () => 
    expect(numberValidator(new FormControl('123'))).toEqual(
      'validateNumber':  'valid': false 
    );
    expect(numberValidator(new FormControl('123456789'))).toEqual(null);
  );

  it('should validate (tedious)', async(() => 
    let fixture = TestBed.createComponent(TestComponent);
    let comp = fixture.componentInstance;
    let debug = fixture.debugElement;
    let input = debug.query(By.css('[name=number]'));

    fixture.detectChanges();
    fixture.whenStable().then(() => 
      input.nativeElement.value = '123';
      dispatchEvent(input.nativeElement, 'input');
      fixture.detectChanges();

      let form: NgForm = debug.children[0].injector.get(NgForm);
      let control = form.control.get('number');

      // just to show a few different ways we can check validity
      expect(control.hasError('validateNumber')).toBe(true);
      expect(control.valid).toBe(false);
      expect(form.control.valid).toEqual(false);
      expect(form.control.hasError('validateNumber', ['number'])).toEqual(true);

      input.nativeElement.value = '123456789';
      dispatchEvent(input.nativeElement, 'input');
      fixture.detectChanges();

      expect(form.control.valid).toEqual(true);
    );
  ));
);

【讨论】:

当我尝试第二种方法时。我没有找到 ngForm 的提供者。我确信这应该是我的错误。你知道这可能是什么问题吗? 获取NgForm 的更好方法是使用debug.query(By.directive(NgForm))。我只是在查看 Angular 源代码测试,以找到我在上面的帖子中所做的方式。但是使用By.directive 可能是更好的方法。

以上是关于Angular2如何对自定义验证器指令进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何对自定义 Wicket 组件进行单元测试

如何对自定义 AJAX 事件进行单元测试

如何对自定义 Jackson JsonSerializer 进行单元测试?

WPF - 对自定义标记扩展进行单元测试

Angular 2 自定义验证单元测试

使用 PyTorch 和 TorchVision 对自定义数据集进行训练-有效-测试拆分