【问题标题】:Angular “Cannot read property 'subscribe' of undefined” in Unit Test单元测试中的角度“无法读取未定义的属性'订阅'”
【发布时间】:2026-01-05 06:40:01
【问题描述】:

我正在使用 Jest 对我的 Angular 应用程序进行单元测试,但我不断收到此错误 TypeError: Cannot read property 'subscribe' of undefined 在线解决方案似乎没有意义或正常工作。这是一些代码:

page-view.component.ts

  @Input() gotPlot!: Observable<void>;
  ...
  ngOnInit() {
    this.initialiseColumnDefs();
    this.gotPlot.subscribe((response) => { //ERROR is occurring on this line
      this.gotPlotValues(response);
    });
  }

page.component.ts

@Component({
  selector: 'page',
  template: `
    <page-view
      [gotPlot]="gotPlotSubject.asObservable()"
    >
    </page-view>
  `,
})

export class PageComponent implements OnInit {
  ...
  public gotPlotSubject: Subject<void> = new Subject<void>();
  ...

  async get_plot(arr: any): Promise<any[]> {

    //This function calls a service and gets 'plotValues'
    (await this.service.get_plot(input)).subscribe((data: any) => {

      //plotValues is set to values gotten from the service here     

      this.gotPlotSubject.next(plotValues);
    });
  }
}

page-view.component.spec.ts

@Component({
  selector: 'page',
  template: `
    <page-view *ngIf="gotPlotSubject.asObservable()" [gotPlot]="gotPlotSubject.asObservable()">
    </page-view>
  `,
})
class PageMock {
  public gotPlotSubject: Subject<void> = new Subject<void>();
  constructor() {}
  ngOnInit() {
    let plotValues: any = [];
    plotValues[0] = 1;
    plotValues[1] = [1, 2, 3];
    plotValues[2] = [2, 3, 4];
    this.gotPlotSubject.next(plotValues);
  }
}

describe('ViewComponent', () => {
  let spectator: Spectator<ViewComponent>;

  const createComponent = createComponentFactory({
    component: ViewComponent,
    declarations: [
      ViewComponent,
      PageMock,
    ],
    imports: [TranslateModule.forRoot(), MaterialModule, AgGridModule, FormsModule],
    providers: [HttpClient, HttpHandler, NGXLogger, NGXMapperService, HttpBackend, NGXLoggerHttpService, LoggerConfig],
    schemas: [NO_ERRORS_SCHEMA],
  });

  beforeEach(() => {
    spectator = createComponent();
  });

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

我的 PageMock 错了吗?如何正确模拟可观察/订阅?有没有更简单的方法可以在不使用 observables 或订阅的情况下做到这一点?订阅和 Observables 似乎让单元测试变得比它应该的更痛苦。

【问题讨论】:

    标签: angular typescript unit-testing mocking observable


    【解决方案1】:

    尝试做

    @Component({
      selector: 'page',
      template: `
        <page-view *ngIf="gotPlotSubject.asObservable() | async" [gotPlot]="gotPlotSubject.asObservable()">
        </page-view>
      `,
    })
    

    查看*ngIf 上的async 管道。 *ngIf 上的可观察值的展开值将始终是真实的。我什至会摆脱asObservable()。我不认为它们是必需的,但您可以尝试一些东西。

    你是对的,使用 RxJS 进行测试可能会很棘手。

    【讨论】:

    • 不幸的是,这对我不起作用。我遇到了同样的错误。
    • 你能调试吗?尝试将console.log('In View Component') 放在ViewComponent 的错误订阅正上方,将console.log('In Mock Component') 放在this.gotPlotSubject.next(plotValues) 正上方。如果In View Component 出现在In Mock Component 之前,我们可以看到顺序颠倒了。如果是这种情况,我会将component: ViewComponent 更改为component: PageMock,因为我觉得有component: ViewComponent 然后在beforeEach 中调用createComponent 会使ViewComponent 中的ngOnInit 先运行,而我们不会'不想那样。
    最近更新 更多