【问题标题】:Unit test fails when stream/event has pipe(takeUntil(destroy))当流/事件有管道时单元测试失败(takeUntil(destroy))
【发布时间】:2021-05-11 07:54:54
【问题描述】:

角度:9.1.13; RxJS:6.6.3;业力:4.3.0;茉莉花核:2.6.2

我们有一个具有服务的组件,它对流和事件进行处理。

通过调用this._destroy.next(),在ngOnDestroy钩子中声明为private _destroy = new Subject()的主题,当它被销毁时,每个此类组件方法都会取消订阅流/事件。

在我们运行单元测试之前,一切似乎都很好。方法和测试示例如下。

尚不清楚为什么使用takeUntil 订阅服务流/事件时测试失败。

(另一个用例)不使用返回具有pipe(takeUntil(destroy)) 的可观察对象的存根

使用 jasmine/karma 和 phantom.js 运行测试时出错

TypeError: undefined is not a constructor (evaluating 'this.service.getServicePackages().pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_9__["takeUntil"])(this._destroy))')

方法示例:

getServicePackages(): void {
 this.service.getServicePackages().pipe(takeUntil(this._destroy)).subscribe(() => ... );
}

测试示例:


beforeAll(() => {
  serviceStub = {
    getServicePackages: () => ({ subscribe: () => ({}) }),
    // v2 -> getServicePackages: () => ({ subscribe: (): Observable<TYPE> => of({}) }),
  }
})

it('...', () => {
  const serviceStub = TestBed.inject(PackageService);

  spyOn(serviceStub, 'getServicePackage').and.callThrough();
  spyOn(component, 'getServicePackage').and.callThrough();

  component.getServicePackage();

  expect(component.getServicePackage).toHaveBeenCalled();
  expect(serviceStub.getServicePackage).toHaveBeenCalled();
})

【问题讨论】:

  • 能否提供代码如何声明 serviceStub?
  • @Andrei,请查看更新的测试示例

标签: javascript angular typescript unit-testing rxjs


【解决方案1】:

如果我们把两行放在一起,问题就很明显了

serviceStub = {
    getServicePackages: () => ({ subscribe: () => ({}) }),
    // v2 -> getServicePackages: () => ({ subscribe: (): Observable<TYPE> => of({}) }),
};
// and then in code of component
serviceStub.getServicePackages().pipe(does not matter what); // here it doesn't have pipe method

我建议返回 observable 本身。如果您还想测试事件 - 返回一个主题。

servicePackagesSubject = new Subject();
serviceStub = {
    getServicePackages: jasmine.createSpy('getServicePackages').and.returnValue(servicePackagesSubject),
  }

【讨论】:

    【解决方案2】:

    我认为这是处理此类案件的最佳方式:

    // As mentioned earlier by @Andrei, it does not matter about the pipe operators. 
    
    // In your test case, create a mock service, return a value, and use it as a useClass method in the providers and simply spyOn your component method. Something like this: 
    
    
    // In your spec file, 
    
    @Injectable() 
    class MockService extends YourOriginalService {
      getServicePackages() {
        // Since you are subscribing, i am assuming this returns an observable, hence
        // the 'of' operator
        
        const mockData = {fill your mockData here};
        return of(mockData);
      }
    }
    
    // In your before each, add the mockService to your providers 
    
    let mockService: YourOriginalService;
    beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [],
          ....
          providers: [
            {
              provide: YourOriginalService,
              useClass: MockService
            }
          ]
          ......
        }).compileComponents();
    
        mockService = TestBed.get(YourOriginalService);
      }));
    
    
    
    /// Now your test case turns to this: 
    
    it('should call the #getServicePackages() method in component', () => {
      
      spyOn(component, 'getServicePackages').and.callThrough();
      component.getServicePackages();
      expect(component.getServicePackages).toHaveBeenCalled();
    
    });
    
    
    // Now if you want to test the 'error' part in the subscribe, you can take care of that in this test case like this: 
    
    it('should call the #getServicePackages() method in component, for error scenario', () => {
      // Assuming its an API Call, otherwise replace the status object with your mock error object
      spyOn(component, 'getServicePackages').and.callThrough();
      spyOn(mockService, 'getServicePackages')
        .and.returnValue(throwError(of({status: 500})));
      component.getServicePackages();
      expect(component.getServicePackages).toHaveBeenCalled();
    
    });
    
    // Note: Please don't mix the service success scenario coverage and service error scenario coverage in the same test case. Use 2 test cases like above. 
    
    
    

    【讨论】:

      猜你喜欢
      • 2015-02-04
      • 2020-02-17
      • 1970-01-01
      • 2023-04-04
      • 2021-07-08
      • 2012-07-12
      • 1970-01-01
      • 2012-09-19
      • 2021-01-30
      相关资源
      最近更新 更多