简体   繁体   English

仅在运行 Angular Jasmine 测试时未定义对 observable 的订阅,但在运行应用程序本身时已定义

[英]Subscription to an observable is undefined only when running Angular Jasmine test, but is defined when running the app itself

I have written a unit test for this function:我为这个函数写了一个单元测试:

getCarsAndSetup(){
    this.getCars();
    this.getFactoryInfo();
}

This is the getCars() function:这是 getCars() 函数:

getCars() {
     const subscription = this.carDetailsService.getAll().subscribe((carDetails) => {
     this.carInfoService.setCars(carDetails);
     subscription.unsubscribe();  <-------------- Here the 
                                               subscription is undefined
                                                when running the test, 
                                                however when running
                                               the app, the subscription 
                                                is defined and
                                                  everything is fine
    });
}

This is the unit test:这是单元测试:

fdescribe('getCarsAndSetup', () => {
    it('should get cars and set them up', () => {
        component.getFactoriesAndUnsubscribe();
        spyOn(component, "getCars");
        spyOn(component, "getFactoryInfo");
        expect(component.getCars).toHaveBeenCalled();
        expect(component.getFactoryInfo).toHaveBeenCalled();
    });
  });

I am using a mock for carDetailsService.我正在使用 carDetailsS​​ervice 的模拟。 This is the getAll() method in the carDetailsService mock:这是 carDetailsS​​ervice 模拟中的 getAll() 方法:

getAll(): Observable<CarModel[]> {
    return Observable.create((observer:any) => {
        observer.next([]);
    });
}

And this is the same method in the REAL carDetailsService:这与 REAL carDetailsS​​ervice 中的方法相同:

getAll(): Observable<CarModel[]> {
    return this.http.get<CarModel[]>(this.carUrl);
}

The problem is that when I run the application itself, the subscription in the getCars() method is defined, I can unsubscribe from it etc. and everything is fine.问题是,当我运行应用程序本身时,getCars() 方法中的订阅已定义,我可以取消订阅等等,一切都很好。

However when I run the tests, this test fails, because for some reason the subscription is undefined in the getCars() function when I try to unsubscribe from it.但是,当我运行测试时,此测试失败,因为由于某种原因,当我尝试取消订阅时,getCars() 函数中未定义订阅。

What could be the reason that the subscription is undefined only when running the test?仅在运行测试时订阅未定义的原因可能是什么? Could it have something to do with the way I've mocked the getAll() function of carDetailsService?这可能与我嘲笑 carDetailsS​​ervice 的 getAll() 函数的方式有关吗?

The problem here is that you rely on synchronous/asynchronous behaviour of your source Observable.这里的问题是您依赖源 Observable 的同步/异步行为。

In your real app your this.carDetailsService.getAll() is a real remote call (asynchronous) so its subscription is assigned to subscription and everything works.在您的真实应用程序中,您的this.carDetailsService.getAll()是一个真正的远程调用(异步),因此它的订阅被分配给subscription并且一切正常。 In your tests however the same call is probably mocked and therefore synchronous so by the time you want to call subscription.unsubscribe() it's still undefined (the subscribe method is still executing and no subscription has been returned yet).然而,在您的测试中,相同的调用可能被模拟,因此是同步的,因此当您要调用subscription.unsubscribe()它仍然undefinedsubscribe方法仍在执行并且尚未返回订阅)。

The easiest thing you can do is instead passing an arrow function to subscribe use function keyword.您可以做的最简单的事情是传递一个箭头函数来subscribe use function关键字。 RxJS binds this inside subscriber handlers to its internal Subscription object (I know it's a bit tricky approach but it's intended to be used this way). RxJS结合this里面用户处理其内部认购对象(我知道这是一个有点棘手的方法,但它打算使用这种方式)。

const that = this;
this.carDetailsService.getAll().subscribe(function(carDetails) { // note the `function` keyword
  that.carInfoService.setCars(carDetails);
  this.unsubscribe();
});

Another method could be using takeUntil with a Subject and completing it inside your subscribe .另一种方法可能是将takeUntil与 Subject 一起使用并在您的subscribe完成它。

This behavior might change in the future: https://github.com/ReactiveX/rxjs/issues/3983这种行为将来可能会改变: https : //github.com/ReactiveX/rxjs/issues/3983

The same problem in a different use-case: RxJs: Calculating observable array length in component不同用例中的相同问题: RxJs: Calculating observable array length in component

While martin's answer did get rid of the error, it helped me discover the actual problem here, which is ridiculously silly.虽然马丁的回答确实消除了错误,但它帮助我发现了这里的实际问题,这太愚蠢了。 I had set up the spies AFTER the actual function call:我在实际的函数调用之后设置了间谍:

fdescribe('getCarsAndSetup', () => {
    it('should get cars and set them up', () => {
        component.getFactoriesAndUnsubscribe();
        spyOn(component, "getCars");
        spyOn(component, "getFactoryInfo");
        expect(component.getCars).toHaveBeenCalled();
        expect(component.getFactoryInfo).toHaveBeenCalled();
    });
  });

When the spies had to be defined BEFORE the actual function call:当必须在实际函数调用之前定义间谍时:

fdescribe('getCarsAndSetup', () => {
    it('should get cars and set them up', () => {
        spyOn(component, "getCars");
        spyOn(component, "getFactoryInfo");
        component.getFactoriesAndUnsubscribe();
        expect(component.getCars).toHaveBeenCalled();
        expect(component.getFactoryInfo).toHaveBeenCalled();
    });
  });

I feel bad that martin spent so much time on this answer and reading the long description I posted, and it turns out the whole problem was just a small oversight.我很难过马丁花了这么多时间在这个答案上并阅读了我发布的长篇描述,结果发现整个问题只是一个小小的疏忽。 But it is what it is.但是它就是这样啊。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Playwright测试只会在调试时通过,但在测试angular app时运行时会失败 - Playwright test will only pass when debugging, but fails when running when testing angular app 如何在observable返回之前调用observable next时测试angular / jasmine中的observable,因为模拟 - How to test an observable in angular/jasmine when the observable next is called before the observable is returned, due to mocks ReferenceError:运行我的 angular 6 通用应用程序时未定义 XMLHttpRequest - ReferenceError : XMLHttpRequest is not defined when running my angular 6 universal app 在运行Angular 2 app的Karma测试时,节点模块中的“系统未定义” - “System is not defined” in node module when running Karma tests of Angular 2 app 对Angular 2组件(angular2-seed)运行Jasmine测试时出错 - Error when running Jasmine tests for Angular 2 Component (angular2-seed) 运行Angular应用时出错 - ERROR when running Angular app 运行`ng test`时,浏览器输出中没有显示的Jasmine测试列表 - List of Jasmine tests not showing in browser output when running `ng test` 从可观察订阅访问时未定义的值 - Value undefined when accessed out of observable subscription 标头未定义。 在运行角度通用时 - Headers is not defined. When running angular universal “语法错误:无效或意外的令牌在<Jasmine> &quot; 运行 Angular 测试时 - "SyntaxError: Invalid or unexpected token at <Jasmine>" when running Angular tests
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM