如何正确进行单元测试(Karma、Jasmine),
valueChanges
的发射会调度FormUpdated
动作?
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [...],
providers: [
{ provide: Store, useValue: MOCK_STORE },
],
declarations: [FormComponent],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
export class FormComponent implements OnInit {
searchForm: FormGroup;
constructor(private readonly fb: FormBuilder, private readonly store: Store<AppState>) {
}
ngOnInit(): void {
this.searchForm = this.fb.group({});
this.searchForm.valueChanges.subscribe(value => this.store.dispatch(new FormUpdated(value)));
}
}
我尝试过这样的事情:
it('should dispatch action for valueChanges', () => {
const spy = spyOn(component['store'], 'dispatch');
spyOn(component.searchForm, 'valueChanges').and.returnValue(of({}));
expect(spy).toHaveBeenCalledTimes(1);
});
但这不起作用——间谍还没有被召唤。
[编辑1] - 基于评论和答案:
问题在于测试的异步性。
ngOnInit
的某些部分调用 setTimeout(() => this.searchForm.get('field').updateValueAndValidity();)
),这会导致发射到 this.searchForm.valueChanges()
,因此 this.store.dispatch
实际上被调用,但在 expect(spy).toHaveBeenCalledTimes(1)
之后。我尝试添加
fakeAsync()
、
tick()
和
flushMicrotasks()
,但结果相同。
it('should dispatch action for valueChanges', () => {
const spy = spyOn(component['store'], 'dispatch');
spyOn(component.searchForm, 'valueChanges').and.returnValue(of({}));
tick();
flushMicrotasks();
expect(spy).toHaveBeenCalledTimes(1);
});
this.searchForm = this.fb.group({description: ['your_input']});
.
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [...],
providers: [
{ provide: Store, useValue: MOCK_STORE },
],
declarations: [FormComponent],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should dispatch action for valueChanges', () => {
const spy = spyOn(TestBed.get(Store<AppState>), 'dispatch')
component.searchForm.controls['your_input'].setValue('test') // This will trigger change
expect(spy).toHaveBeenCalledTimes(1);
});
valueChanges
无法直接监视,b/c“‘string’类型的参数不可分配给‘never’类型的参数”。我通过添加一个管道,然后用模拟返回值监视管道来解决这个问题。因此,对于您的情况,请在
valueChanges
中的
ngOnInit()
之前添加一个管道:
this.searchForm.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(value => this.store.dispatch(new FormUpdated(value)));
然后在单元测试中,监视管道:
spyOn(component.searchForm.valueChanges, 'pipe').and.returnValue(of({}));