【问题标题】:UT not pass due to undefined FormArray control while the control must be definedUT 由于未定义的 FormArray 控件而未通过,而必须定义该控件
【发布时间】:2020-04-22 00:09:36
【问题描述】:

我有一个研讨会编辑组件(按顺序):

  • 构建表单
  • 检索要编辑的创意工坊
  • 使用创意工坊值更新表单值

代码如下:

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 看起来像:

[
  {
    Key: 1,
    Title: 'title',
    Description: 'description',
  },
]

所以,上面的所有代码都可以正常工作,但我正在尝试对 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 被调用,但没有像它必须做的那样推动一个组。

我重复一遍,但在实际应用中它按预期工作。

【问题讨论】:

  • updateFormValues 就在第一行之前,在它之后执行console.log(this.form)debugger。使用fit 运行测试并立即打开开发人员工具(按 F12)。 debugger 应该被触发,您可以在控制台中看到this.form 的值。从错误消息来看,我敢打赌this.form 在那个时候是未定义的。在您的测试中直接调用updateFormValues 之前,可能没有调用buildForms
  • this.formthis.discussesForm 不同。在我的测试中,第一次期望通过,所以这意味着 buildForm 被调用。我无法使用浏览器(仅 cli)打开测试,因此调试它有点困难。
  • 对不起,我误解了。
  • 我会找到一种使用浏览器或某种调试方法进行调试的方法,以便使此类任务更容易。但我想我知道问题出在哪里。在您的测试中,您正在监视addDiscussion。这只会为该函数创建一个“观察者”,而不是实际调用它的实现。要同时拥有“观察者”并调用该函数,您可以使用spyOn(component, 'addDiscussion').and.callThrough()。其实你可以去掉这个spyOn,我觉得你不需要。
  • 哦,我使用 spyOn 来测试 hasBeenCalledTimes(2) 但我现在不再需要它了,你说得对。

标签: angular jasmine karma-jasmine angular-unit-test


【解决方案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);
});

除此之外,正如 cmets 中已经提到的,addDiscussion 不再需要被监视,因为您的测试依赖于它。完成此操作后,您的测试应该可以正常工作了。

【讨论】:

  • 是的!有时我认为问题不是来自我的 ts 而不是来自我的测试...我只需要添加 addEmptyDiscussion() 因为用户可能会在表格中添加空行^^谢谢。
  • 任何时候 :) 无需创建新功能即可添加空讨论。相反,如果您只调用 addDiscussion 而没有任何参数,就足够了。我更新了答案,如果您不将任何参数传递给addDiscussion,则discussion 默认为空对象,因此在表中创建一个带有null 值的空行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
相关资源
最近更新 更多