Angular 由于未定义FormArray控件,而必须定义控件,因此UT未通过
我有一个车间编辑组件(按顺序):Angular 由于未定义FormArray控件,而必须定义控件,因此UT未通过,angular,jasmine,karma-jasmine,angular-unit-test,Angular,Jasmine,Karma Jasmine,Angular Unit Test,我有一个车间编辑组件(按顺序): 构建表单 检索要编辑的工作坊 使用车间值更新表单值 代码如下: ngOnInit() { this.buildForms(); this.initialize(); } async initialize(): Promise<void> { const id = this.route.snapshot.params.id; this.workshop = await this.workshopService.find(id);
- 构建表单
- 检索要编辑的工作坊
- 使用车间值更新表单值
ngOnInit() {
this.buildForms();
this.initialize();
}
async initialize(): Promise<void> {
const id = this.route.snapshot.params.id;
this.workshop = await this.workshopService.find(id); // in real this is in a trycatch block
this.updateFormValues();
}
buildForms(): void {
this.form = ... // not important, this is not the problem
this.discussesForm = this.formBuilder.group({
array: this.formBuilder.array([], Validators.required),
});
}
updateFormValues(): void {
this.form.patchValue(this.workshop);
this.workshop.ListDebates.forEach((discussion, index) => {
this.addDiscussion();
(this.discussesForm.get('array') as FormArray).at(index).patchValue({ // This line will throw error while UT.
title: discussion.Title, description: discussion.Description, key: discussion.Key,
});
});
}
addDiscussion(): void {
(this.discussesForm.get('array') as FormArray).push(this.formBuilder.group({
title: [null],
description: [null],
key: [null],
});
}
因此,上面的所有代码都可以正常工作,但我正在尝试对updateFormValues方法进行单元测试
这就是我所尝试的:
it('should update form values', () => {
spyOn(component, 'addDiscussion');
component.workshop = { Title: 'fake title', ListDebates: [
{ Key: 1, Title: 'fake', Description: 'fake' },
{ Key: 2, Title: 'fake', Description: 'fake' },
]} as any as IColabEvent;
component.updateFormValues();
expect(component.form.value.Title).toEqual('fake title'); // test OK
expect((component.discussesForm.get('array') as FormArray).controls.length).toEqual(2); // test KO, expected 0 to be 2
expect((component.discussesForm.get('array') as FormArray).at(0).value).toEqual(...); // test KO (not runned)
});
每次出现错误:无法读取未定义的属性“patchValue”(在updateFormValues方法中)
我尝试了很多方法(以及随机添加的方法,比如添加fixture.detectChanges()),但我没有找到解决方法
奇怪的是addDiscussion被调用了2次,所以我想知道为什么我的FormArray控件没有定义
我已经调用了console.log()一些东西,它看起来像是调用了addDiscussion,但并没有像它必须做的那样推动一个组
我重复我自己的话,但在真正的应用程序中,它是按预期工作的。不是您的测试用例出了问题,而是您的代码出了问题。您无需先使用
addDiscussion
创建具有null
值的对象,然后使用patchValue
设置值。相反,在创建表单组本身时设置这些值。更改addDiscussion
函数以接受discussion
参数
addDiscussion(discussion={}):无效{
this.discussesForm.get('array').push(this.formBuilder.group({
标题:讨论。标题| |空,
description:discussion.description | | null,
键:讨论。键| |空
}));
}
然后在updateFormValues
中,在foreach
循环中,去掉patchValue
代码,转而传递讨论
this.workshop.listDiversations.forEach(discussion=>{
这是讨论;
});
除此之外,正如评论中已经提到的,不再需要监视
addDiscussion
,因为您的测试依赖于它。完成后,您的测试应该可以正常工作。在第一行前面的updateFormValues
中,执行console.log(this.form)
并在它之后执行调试器。使用fit
运行测试,并立即打开开发人员工具(按F12)。调试器
应该被触发,您可以在控制台中看到this.form
的值。根据错误消息判断,我打赌this.form
在该实例中没有及时定义。在测试中直接调用updateFormValues
之前,可能没有调用buildForms
。此表单与此表单不同。DiscusseForm
。在我的测试中,第一个expect pass意味着调用buildForm
。我无法使用浏览器(仅cli)打开测试,因此调试有点困难。抱歉,我误解了。我会找到一种使用浏览器或某种调试方法进行调试的方法,以便使类似任务更容易。但我想我知道问题是什么。在测试中,您正在监视addDiscussion
。这将只是为该函数创建一个“观察者”,而不是实际调用其实现。要同时拥有“watcher”和调用函数,您可以执行spyOn(component,'addDiscussion')。和.callThrough()
。事实上,你可以扔掉这个间谍,我想你不需要它。哦,我用间谍来测试已经过了很多次了,但我现在不再需要它了。你是对的。是的!有时我不认为问题来自我的ts,而不是我的测试。。。我只需要添加addEmptyDiscussion()
,因为用户可能会在表中添加空行^^^谢谢。随时:)无需创建新函数来添加空讨论。相反,如果只单独调用addDiscussion
,而不使用任何参数,就足够了。我更新了答案,因此如果不将任何参数传递给addDiscussion
,则discussion
默认为空对象,从而在表中创建一个带有null
值的空行。
it('should update form values', () => {
spyOn(component, 'addDiscussion');
component.workshop = { Title: 'fake title', ListDebates: [
{ Key: 1, Title: 'fake', Description: 'fake' },
{ Key: 2, Title: 'fake', Description: 'fake' },
]} as any as IColabEvent;
component.updateFormValues();
expect(component.form.value.Title).toEqual('fake title'); // test OK
expect((component.discussesForm.get('array') as FormArray).controls.length).toEqual(2); // test KO, expected 0 to be 2
expect((component.discussesForm.get('array') as FormArray).at(0).value).toEqual(...); // test KO (not runned)
});