簡體   English   中英

無法理解錯誤:TypeError:無法讀取未定義的屬性“訂閱”

[英]Cant understand the error: TypeError: Cannot read property 'subscribe' of undefined

我編寫了一個實現來從 API 調用中獲取數據。 但是,在測試功能時,即使在編寫任何有意義的測試用例之前,我也會收到以下錯誤:

TypeError: Cannot read property 'subscribe' of undefined
    at DataComponent.ngOnInit (http://localhost:9876/_karma_webpack_/webpack:/src/app/dashboard/job/job.component.ts:48:10)
    at callHook (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:3405:1)
    at callHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:3375:1)
    at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:3327:1)
    at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8573:1)
    at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8672:1)
    at tickRootContext (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9885:1)
    at detectChangesInRootView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9910:1)
    at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10320:1)
    at ComponentFixture._tick (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:243:1)

我不確定我錯過了什么,任何幫助將不勝感激。 我查看了以下內容以獲得一些理解:

和其他一些參考資料。

這是我的代碼文件。 我已經刪除了我認為與手頭的問題無關的代碼的某些部分。

dataService.ts 代碼:

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { IData } from '../model/data.model';
import { Observable, throwError } from 'rxjs';
import {catchError, tap} from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class DataService {

  constructor(private http: HttpClient) { }

  public getData(): Observable<IData[]>{
    return this.http.get<IData[]>('url')
    .pipe(
      tap(data => console.log('Data Received')),
      catchError(this.handleError)
    );
  }
  private handleError(err: HttpErrorResponse){
   //handle error code
  }
}

我正在測試的組件-> data.component.ts 代碼:

import { Component, OnInit, Input} from '@angular/core';
import { IData } from '../../model/data.model';
import {DataService} from '../../service/data.service';

@Component({
  selector: 'app-job',
  templateUrl: './job.component.html',
  styleUrls: ['./job.component.css']
})
export class JobComponent implements OnInit {

   @Input() appId: string;

   jobs: IData[] = [];
   
   constructor(   private dataService: DataService ) {}

   ngOnInit(): void {
      this.dataService.getData().subscribe({
         next: data => {
            this.data = data;
         },
         error: err => this.errorMessage = err
      });
   }
//other implementation
}

測試文件:data.spec.ts:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataComponent } from './job.component';
import { IData } from 'src/app/model/job.model';
import { DataService } from 'src/app/service/job-data.service';
import { of, Observable } from 'rxjs';
import { NO_ERRORS_SCHEMA } from '@angular/core';

describe('DataComponent', () => {
  let component: DataComponent;
  let fixture: ComponentFixture<DataComponent>;
  let mockDataService ;
  let JOBS: IData[];
  

  beforeEach(async () => {
    mockJobDataService = jasmine.createSpyObj(['getData']);
    await TestBed.configureTestingModule({
      declarations: [ DataComponent ],
      providers: [
        {provide: DataService, useValue: mockDataService}
      ]
    })
    .compileComponents()
    .then(() => {
      DATA = [{id: 'CJH'}];
      fixture = TestBed.createComponent(DataComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();  //updates bindings
    });
  });

  it('should return true',() => {
        expect(true).toBe(true);
  })
  
});

當我刪除fixture.detectChanges()時,錯誤被刪除。 但據我了解,即使我在測試中的任何地方使用此調用,測試用例也應該有效。

您正在使用mockJobDataService = jasmine.createSpyObj(['getData']); 並使用此{provide: DataService, useValue: mockDataService}正確注冊它。 此時,您的組件應該被正確地創建並注入了您的虛假服務。 問題是您沒有在假服務上設置預期的方法調用。

只要您在調用fixture.detectChanges()之前執行此操作,類似以下的操作就可以解決問題。 由於您不包括IJob界面的形狀,因此我無法准確告訴您,但我通過強制轉換( ({} as IJob) )使其與 typescript 一起使用。

import { of } from 'rxjs';

mockJobDataService.getData.and.returnValue(of([({} as IJob)]));

這告訴 jasmine 任何使用這個假數據服務的東西,在調用 getData 方法時,該方法的返回值應該是of([({} as IJob)]) (這是一個 IJob 數組類型的 observable)。

隨着您前進並編寫實際測試您的組件的測試,您可能希望將模擬方法和“detectChanges”調用移動到每個測試中,以便您可以為每個測試提供不同的假數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM