You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular单元测试中FormBuilder未定义问题及类型安全诉求

Angular组件单元测试报错,需保留表单字段初始化写法以维持类型安全

组件代码 (.ts)

import {Component, Inject} from '@angular/core';
import {FormBuilder, Validators} from '@angular/forms';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {IValueAndCurrency} from '@model/IValueAndCurrency';

@Component({
  selector: 'app-top-up-amount-change-dialog',
  templateUrl: './top-up-amount-change-dialog.component.html',
  styleUrls: ['./top-up-amount-change-dialog.component.scss'],
})
export class TopUpAmountChangeDialogComponent {
  topupAmountFormGroup = this.fb.group({
    topupAmount: [this.data.topupAmount, {
      validators: [
        Validators.required,
        Validators.min(0),
      ]
    }],
  })

  constructor(
    private dialogRef: MatDialogRef<TopUpAmountChangeDialogComponent>,
    private fb: FormBuilder,
    @Inject(MAT_DIALOG_DATA)
    public data: {
      topupAmount: IValueAndCurrency;
      possibleAmounts: IValueAndCurrency[];
    },
  ) {
  }

}

单元测试代码

import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {TopUpAmountChangeDialogComponent} from './top-up-amount-change-dialog.component';
import {FormBuilder, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {HttpClientModule} from '@angular/common/http';
import {MATERIAL_MODULES} from 'src/app/app.consts';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {APP_CONFIG} from "../../../../../../../appConfig.injectortoken";
import {TestAppConfigJson} from "../../../../../../app.component.spec";
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {IValueAndCurrency} from "../../../../../../common/models/IValueAndCurrency";
import {Currency} from "../../../../../../common/models/enums/currency.enum";

fdescribe('TopUpAmountChangeDialogComponent', () => {
  let component: TopUpAmountChangeDialogComponent;
  let fixture: ComponentFixture<TopUpAmountChangeDialogComponent>;
  const matRefSpy = jasmine.createSpyObj('matRefSpy', ['close']);
  const dialogData: { topupAmount: IValueAndCurrency, possibleAmounts: IValueAndCurrency[] } = {
    topupAmount: {
      value: 10,
      currencyCode: Currency.EUR
    },
    possibleAmounts: [
      {
        value: 0,
        currencyCode: Currency.EUR
      },
      {
        value: 0,
        currencyCode: Currency.USD
      }
    ]
  };

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      imports: [
        FormsModule,
        BrowserAnimationsModule,
        MATERIAL_MODULES,
        ReactiveFormsModule,
        HttpClientModule,
      ],
      declarations: [TopUpAmountChangeDialogComponent],
      providers: [
        FormBuilder,
        {provide: APP_CONFIG, useValue: TestAppConfigJson},
        {provide: MatDialogRef, useValue: matRefSpy},
        {provide: MAT_DIALOG_DATA, useValue: dialogData},
      ],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TopUpAmountChangeDialogComponent);
    component = fixture.componentInstance;
    component.data = dialogData;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

测试报错信息

Chrome 110.0.0.0 (Linux x86_64) TopUpAmountChangeDialogComponent should create FAILED
        TypeError: Cannot read properties of undefined (reading 'group')
            at new TopUpAmountChangeDialogComponent (src/app/modules/.../top-up-amount-change-dialog/top-up-amount-change-dialog.component.ts:12:34)

需求说明

将表单控件初始化逻辑移至构造函数后测试可正常运行,但希望保留当前写法,借助FormBuilder隐式推断类型以维持类型安全,避免手动定义接口造成代码重复。


内容的提问来源于stack exchange,提问作者ForestG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:54:23