比如我们当前创建了一个如下的异步验证器,我们想要写一个单元测试来保证其准确性。
vehicleBrandNameNotExist(): AsyncValidatorFn {
return (control: AbstractControl): Observable => {
if (control.value === '') {
return of(null);
}
return this.vehicleBrandService.existByName(control.value).pipe(map(exists => exists ? {vehicleBrandNameExist: true} : null));
};
}
我们再mockApi中设置了如果name为‘车辆品牌’则返回true,若为‘车辆’则返回false,其余情况随即返回。
if(name === '车辆品牌') {
console.log('return true');
return true;
}
if(name === '车辆')
return false;
return randomNumber(5) < 2;
起初想的是只要像这样在单元测试中创建一个formControl然后再设置它的值为'车辆品牌'然后再断定formControl.errors.vehicleBrandNameExist
为true即可,但是系统会发生报错提示formControl.errors.vehicleBrandNameExist
为undefined;
之后又加入了setTimeout进行延时处理
beforeEach(() => {
asyncValidate = TestBed.inject(VehicleBrandAsyncValidator);
service = TestBed.inject(VehicleBrandService);
});
fit('should create an instance', async () => {
expect(asyncValidate).toBeTruthy();
let formControl = new FormControl('', asyncValidate.vehicleBrandNameNotExist());
formControl.setValue('车辆品牌');
setTimeout(() => console.log(formControl.errors.vehicleBrandNameExist), 500);
});
经过输出发现还是为undefined.之后我有分别在验证器C层,M层,和mockApi中进行输出相应的断点,发现根本没有执行到mockApi中,只执行到了M层。
之后我又尝试在相应的模块的单元测试中进行如下测试,发现可以实现我们想要的效果。
beforeEach(() => {
fixture = TestBed.createComponent(AddComponent);
asyncValidate = TestBed.inject(VehicleBrandAsyncValidator);
component = fixture.componentInstance;
fixture.detectChanges();
});
fit('should create', () => {
component.formGroup.get(component.formKeys.name).setValue('车辆品牌');
setTimeout(() => console.log(component.formGroup.get(component.formKeys.name).errors.vehicleBrandNameExist), 100);
});
这时问题就出现了,我们只是把formControl声明在了component中就可以实现我们想要的效果,formControl只是改变了获取方式——从直接创建获取变成了在component中创建,再通过component获取。为什么就会出现这样的结果呢。
在此期间还可能遇到以下问题:
let asyncValidator: VehicleBrandAsyncValidator;
let formControl = new FormControl('', asyncValidator.vehicleBrandNameNotExist() );
formControl.setValue('车辆品牌');
如果我们这样使用VehicleBrandAsyncValidator
的话会发生报错,我们会发现asyncValidator
为空,我们需要手动通过一下代码将VehicleBrandAsyncValidator注入进来。
asyncValidate = TestBed.inject(VehicleBrandAsyncValidator);
我很还有可能在执行上述代码时可能什么都不会执行即不会触发验证器,那么很有可能是由于在
let formControl = new FormControl('', asyncValidator.vehicleBrandNameNotExist() );
中我们将其写为了
let formControl = new FormControl('', asyncValidator.vehicleBrandNameNotExist );
这种情况在C层编辑器会告诉我们类型不匹配,但是在单元测试中不会。