簡體   English   中英

單元測試時出錯 - TypeError:無法讀取未定義的屬性'cityWeather'

[英]Error while unit test - TypeError: Cannot read property 'cityWeather' of undefined

在Component.ts中,

this.dataService.currentCity.subscribe(info => {
  this.cities = info;
});

this.dataService.currentSelectedCity.subscribe(index => {
  this.selectedCityIndex = index;
});

this.selectedCityInfo = this.cities[this.selectedCityIndex];
this.selectedCityWeatherList = this.selectedCityInfo.cityWeather.list;

我試圖在ngOnInit()測試這段代碼。 但我不確定如何測試此代碼。 在這里,我的另一個組件是使用我在這個組件的`ngOnInit()中訂閱的行為主題向我發送一個對象數組以及所選項目的索引。 並嘗試訪問所選對象中的cityWeather屬性。

在Spec.ts中,我嘗試了類似這樣的東西,我確信這不是一種正確的測試方法。

it("should handle ngOnInit", async(() => {
        let response;
        const dataService = fixture.debugElement.injector.get(DataService);  
        spyOn(dataService, 'currentCity').and.returnValue(of(response));
        component.ngOnInit();
        expect(component.cities).toEqual(response);
    }));

當我運行應用程序時,我得到了輸出,但是當我測試ngoninit函數時,我沒有得到訂閱的響應。 我收到以下錯誤。 Failed: Cannot read property 'cityWeather' of undefined TypeError: Cannot read property 'cityWeather' of undefined

在data.service.ts中

private citySubject = new BehaviorSubject<any>('');
currentCity = this.citySubject.asObservable();
private selectedCity = new BehaviorSubject<any>('');
currentSelectedCity= this.selectedCitySubject.asObservable();

sendCityWeatherInfo(info,index) {
  this.citySubject.next(info);
  this.selectedCitySubject.next(index);
}

我在這樣的組件中調用它(傳遞一個對象和索引數組)

this.dataService.sendCityWeatherInfo(this.cities, index);

錯誤不在你的測試中,它在這一行:

this.selectedCityInfo = this.cities[this.selectedCityIndex];

this.citiesthis.selectedCityIndex尚未定義 - 您訂閱了dataService ,它將更新它們,但服務沒有運行。 此外,當服務運行時, this.selectedCityInfo將不會更新。

而是在收到新數據時更新這些值。 一個簡單的解決方案是

  this.dataService.currentCity.subscribe(info => {
    this.cities = info;
    this.updateSelectedCity();
  });

  this.dataService.currentSelectedCity.subscribe(index => {
    this.selectedCityIndex = index;
    this.updateSelectedCity();
  });
}

...

updateSelectedCity() {
  this.selectedCityInfo = this.cities[this.selectedCityIndex];
  this.selectedCityWeatherList = this.selectedCityInfo.cityWeather.list;
}

為了測試,沒有測試this.selectedCityInfothis.selectedCityWeatherList 我不熟悉測試庫,但你可能想要一些像expect(component.selectedCityInfo).toEqual(...) ,與this.selectedCityWeatherList

由於您正在處理本質上是異步的可觀察流,因此this.citiesthis.selectedCityIndex可以按未知順序或在未知時間更新。

因此,下面的同步代碼將祈禱有可能處理未定義的值。

this.selectedCityInfo = this.cities[this.selectedCityIndex];
this.selectedCityWeatherList = this.selectedCityInfo.cityWeather.list;

例如,當您嘗試分配this.selectedCityInfothis.citiesthis.selectedCityIndex可能未定義,並且賦值將失敗。 更重要的是,在您的服務中,您使用空字符串初始化兩個行為主題..這是不同的數據類型。

這種設計引發了各種問題和意外行為。 我建議避免以這種方式構建數據流。

相反,我建議使用combineLatest函數在一個訂閱中組合兩個observable,或者通過以下方式重構位:

因為在你的服務updateSelectedCity方法中,你同時從兩個observable發出,也許(如果它適合你的應用程序),在單個observable中發出這兩個值會更容易嗎? 然后我們就知道兩個值肯定都到了,我們可以在subscribe回調函數中執行this.selectedCityInfothis.selectedCityWeatherList賦值。

在服務中:

/* you can keep private property and recast it to Observable,
but you can also subscribe to Subjects and BehaviorSubjects directly
since they extend Observable class.
So that's what I'm doing here */

cityWeatherInfo$ =  = new BehaviorSubject<any>({ info: null, index: null });

sendCityWeatherInfo(info,index) {
  this.cityWeatherInfo$.next({ info, index });

}

在組件中:

this.dataService.cityWeatherInfo$
  .subscribe(({ info, index }) => {
    if (info !== null && index !== null) {
      this.cities = info;
      this.selectedCityIndex = index;
      this.selectedCityInfo = this.cities[this.selectedCityIndex];
      this.selectedCityWeatherList = this.selectedCityInfo.cityWeather.list;
    }    
  });

PS我不知道您的所有應用程序的要求,但也許您可以在服務中使用簡單的Subject而不是BehaviorSubject 這樣它就不會發出初始的空值, if (info !== null && index !== null)檢查則沒有必要。

暫無
暫無

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

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