英文:
UT not pass due to undefined FormArray control while the control must be defined
问题
我有一个名为workshop-edit的组件,它按顺序执行以下操作:
- 构建表单
- 检索要编辑的研讨会
- 使用研讨会的值更新表单值
以下是代码:
ngOnInit() {
this.buildForms();
this.initialize();
}
async initialize(): Promise<void> {
const id = this.route.snapshot.params.id;
this.workshop = await this.workshopService.find(id); // 在实际应用中,这在trycatch块中
this.updateFormValues();
}
buildForms(): void {
this.form = ... // 不重要,这不是问题所在
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({ // 这一行将在单元测试时引发错误。
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],
}));
}
workshop.ListDebates看起来像这样:
[
{
Key: 1,
Title: 'title',
Description: 'description',
},
]
所以上面的所有代码都正常工作,但我正在尝试对updateFormValues方法进行单元测试。
这是我尝试过的内容:
it('应该更新表单值', () => {
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'); // 测试通过
expect((component.discussesForm.get('array') as FormArray).controls.length).toEqual(2); // 测试不通过,期望为2,实际为0
expect((component.discussesForm.get('array') as FormArray).at(0).value).toEqual(...); // 测试不通过(未运行)
});
每次我都会收到错误消息:无法读取未定义的属性'patchValue'(在updateFormValues方法中)。
我尝试了很多方法(还有像添加fixture.detectChanges()这样的随机方法),但我找不到解决方法。
奇怪的是,addDiscussion被调用了2次,所以我不明白为什么我的FormArray控件未定义。
我已经使用console.log()打印了一些内容,看起来addDiscussion被调用了,但没有像应该的那样推送一个组。
我再次重申,在实际应用中,它按预期工作。
英文:
I have a workshop-edit component that (in order):
- Build the form
- Retrieve the workshop to edit
- Update form values with workshop values
Here is the code:
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],
});
}
workshop.ListDebates look like:
[
{
Key: 1,
Title: 'title',
Description: 'description',
},
]
So, all the code above works fine, but i'm trying to unit test the updateFormValues method.
This is what I tried:
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)
});
Everytime I get error: Cannot read property 'patchValue' of undefined (in the updateFormValues method).
I've tried lots of things (and random things like adding fixture.detectChanges()) but I don't find a way to fix it.
What is weird is that addDiscussion is called 2 times, so I wonder why my FormArray control is undefined.
I've console.log() some things and it look like addDiscussion is called but isn't pushing a group like it must does.
I repeat myself but in the real app it's working as intended.
答案1
得分: 1
与您的测试用例没有问题,实际上是您的代码存在问题。您无需首先使用 addDiscussion
创建一个具有 null
值的对象,然后使用 patchValue
来设置这些值。而是在创建表单组时即可设置这些值。将您的 addDiscussion
函数修改为接受 discussion
参数。
addDiscussion(discussion = {}): void {
this.discussesForm.get('array').push(this.formBuilder.group({
title: discussion.Title || null,
description: discussion.Description || null,
key: discussion.Key || null
}));
}
然后在 updateFormValues
中的 foreach
循环中,删除 patchValue
代码并传递 discussion
参数。
this.workshop.ListDebates.forEach(discussion => {
this.addDiscussion(discussion);
});
除此之外,如评论中已经提到的,不再需要对 addDiscussion
进行监视,因为您的测试依赖于它。完成这些修改后,您的测试应该可以正常工作。
英文:
Rather than something being wrong with your test cases, it is in fact your code that has an issue. There is no need for you to use addDiscussion
first to create an object with null
values and then use patchValue
to set the values. Instead, set the values as you create the form group itself. Change your addDiscussion
function to accept the discussion
parameter.
addDiscussion(discussion = {}): void {
this.discussesForm.get('array').push(this.formBuilder.group({
title: discussion.Title || null,
description: discussion.Description || null,
key: discussion.Key || null
}));
}
Then in updateFormValues
, in your foreach
loop, get rid of the patchValue
code and pass discussion
instead.
this.workshop.ListDebates.forEach(discussion => {
this.addDiscussion(discussion);
});
Apart from this, as already mentioned in the comments, the addDiscussion
no longer needs to be spied upon since your test depends on it. Once this is done, your tests should be working.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论