【问题标题】:Error while unit test - TypeError: Cannot read property 'cityWeather' of undefined单元测试时出错-TypeError:无法读取未定义的属性“cityWeather”
【发布时间】:2019-05-28 13:50:36
【问题描述】:

在 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);

【问题讨论】:

  • 可以添加完整的组件代码吗?那么 spyOn spyOn(dataService, 'currentSelectedCity') 呢?你是否也返回了一个可观察的值?部分问题可能是 this.selectedCityIndex 仍未定义,因为 observable 尚未返回。
  • @HarijsDeksnis 我已经更新了我的代码。请检查一下。

标签: javascript angular typescript unit-testing


【解决方案1】:

错误不在你的测试中,它在这一行:

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 也是如此。

【讨论】:

  • 我仍然遇到同样的错误。当我根据您的建议更改我的代码时,我在浏览器中也遇到了同样的错误。以前我只有在测试时才得到它(ng test)。
【解决方案2】:

由于您正在处理本质上是异步的可观察流, this.citiesthis.selectedCityIndex 可以以未知的顺序或未知的时间更新。

因此,下面的同步代码很可能会处理未定义的值。

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

例如,当您尝试分配 this.selectedCityInfo 时,this.citiesthis.selectedCityIndex 可能未定义并且分配将失败。 更重要的是,在您的服务中,您使用空字符串初始化您的两个行为主题......这是不同的数据类型。

这种设计会引发各种问题和意想不到的行为。 我建议不要以这种方式构建数据流。

相反,我建议使用combineLatest 函数将两个可观察对象合并到一个订阅中,或者通过以下方式重构位:

由于在您的服务 updateSelectedCity 方法中您同时从两个可观察对象发出,也许(如果它适合您的应用程序)在单个可观察对象中发出两个值会更容易?然后我们就会知道这两个值肯定会到达,我们可以在订阅回调函数中进行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;
    }    
  });

附:我不知道您应用程序的所有要求,但也许您可以在服务中使用简单的Subject 而不是BehaviorSubject。这样它就不会发出初始的空值,也不需要if (info !== null &amp;&amp; index !== null) 检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-17
    • 2019-09-16
    • 2018-04-18
    • 2018-11-11
    • 2021-01-22
    • 2018-07-27
    • 2018-02-14
    • 2019-08-06
    相关资源
    最近更新 更多