当前位置: 首页 > Web前端 > HTML

为异步验证器编写单元测试

时间:2023-03-27 23:11:59 HTML

例如,我们目前创建一个异步验证器如下,我们要编写一个单元测试来保证其准确性。vehicleBrandNameNotExist():AsyncValidatorFn{return(control:AbstractControl):Observable=>{if(control.value===''){返回(null);}returnthis.vehicleBrandService.existByName(control.value).pipe(map(exists=>exists?{vehicleBrandNameExist:true}:null));};我们将mockApi设置为如果名称为'vehiclebrand'则返回true,如果名称为'vehicle'则返回false,在其他情况下立即返回。if(name==='车辆品牌'){console.log('returntrue');返回真;}if(name==='vehicle')returnfalse;returnrandomNumber(5)<2;一开始以为在单元测试中这样创建一个formControl然后将它的值设置为'vehiclebrand'然后判断formControl.errors.vehicleBrandNameExist为true,但是系统会报错提示formControl.errors.vehicleBrandNameExist为true不明确的;之后添加了用于延迟处理的setTimeoutbeforeEach(()=>{asyncValidate=TestBed.inject(VehicleBrandAsyncValidator);service=TestBed.inject(VehicleBrandService);});fit('应该创建一个实例',async()=>{expect(asyncValidate).toBeTruthy();letformControl=newFormControl('',asyncValidate.vehicleBrandNameNotExist());formControl.setValue('车辆品牌');setTimeout(()=>console.log(formControl.errors.vehicleBrandNameExist),500);});输出后发现还是undefined。之后我在verifierC层、M层、mockApi分别输出相应的断点,发现根本没有在mockApi执行,只执行了M层。然后尝试在对应模块的单元测试中进行如下测试,发现可以达到想要的效果。beforeEach(()=>{fixture=TestBed.createComponent(AddComponent);asyncValidate=TestBed.inject(VehicleBrandAsyncValidator);component=fixture.componentInstance;fixture.detectChanges();});fit('应该创建',()=>{component.formGroup.get(component.formKeys.name).setValue('车辆品牌');setTimeout(()=>console.log(component.formGroup.get(component.formKeys.name).errors.vehicleBrandNameExist),100);});这时候,问题就来了,我们只是在组件中声明了formControl就可以达到我们想要的效果,formControl只是改变了获取的方式——从直接创建获取到在组件中创建并通过component获取。为什么会有这样的结果呢?组件中有什么特殊的机制吗?最后问了老师,发现并没有什么特别的机制。如果仔细观察两者的区别,我们会发现在组件中,我们声明了this.formGroup.addControl(this.formKeys.name,newFormControl('',Validators.required,this.vehicleBrandAsyncValidator.vehicleBrandNameNotExist()));在单元测试中:让formControl=newFormControl('',asyncValidate.vehicleBrandNameNotExist());参数位置错误,第二个参数是同步验证器,第三个参数是异步验证器。我们可以看到formControl的构造函数:constructor(formState?:any,validatorOrOpts?:ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,asyncValidator?:AsyncValidatorFn|AsyncValidatorFn[]|null);错误,我一直以为小编会直接指出这种错误,或者会报相应的错误,但是确实会出现像上面这样的情况,所以我们在调用一些函数或者初始化对象的时候,首先要弄清楚它的参数是什么不能仅基于先前的经验。这期间也可能会遇到以下问题:letasyncValidator:VehicleBrandAsyncValidator;让formControl=newFormControl('',asyncValidator.vehicleBrandNameNotExist());formControl.setValue('汽车品牌');如果我们这样使用VehicleBrandAsyncValidator会报错,我们会发现asyncValidator是空的,需要通过下面的代码手动注入VehicleBrandAsyncValidator。asyncValidate=TestBed.inject(VehicleBrandAsyncValidator);我很可能上面的代码执行的时候什么都没有执行,也就是不会触发validator,所以很有可能是由于letformControl=newFormControl('',asyncValidator.vehicleBrandNameNotExist());我们把它写成letformControl=newFormControl('',asyncValidator.vehicleBrandNameNotExist);在这种情况下,C级编辑器会告诉我们类型不匹配,但不会在单元测试中。上面用setTimeout加延迟的方法可以换成getTestScheduler().flush()方法手动返回数据。这是因为我错误地认为getTestScheduler().flush()不适用于子单元测试。