繁体   English   中英

使用可观察的和使用异步的声明性方法测试 angular 组件时出现 TypeError pipe is not a function

[英]Getting TypeError pipe is not a function while testing angular component using observable with declarative approach using async

运行测试时,我收到“TypeError:this.dashboardService.serviceAgents$.pipe is not a function”错误。

  • ServiceDashboard 页面代码如下:

     import { Component } from '@angular/core';
     import { ServiceDashboardService } from '../services/service-dashboard.service';
     import { tap } from 'rxjs/operators';
     import { ServiceAgent } from '../interfaces/service-agent';
     @Component({
         selector: 'app-service-dashboard',
         templateUrl: './service-dashboard.page.html',
         styleUrls: ['./service-dashboard.page.css'],
     })
     export class ServiceDashboardPage {
         serviceAgentSlideOptions: any = {
             slidesPerView: 4
         };
         serviceAgents$ = this.dashboardService.serviceAgents$
             .pipe(
                 tap(serviceAgents => {
                     this.serviceAgentSlideOptions.slidesPerView = serviceAgents.length < 4 ? serviceAgents.length : 4;
                 })
             );
         constructor(private dashboardService: ServiceDashboardService) { }
     }  
  • 以下是 ServiceDashboardPage 的单元测试代码。
      import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
      import { async, ComponentFixture, TestBed } from '@angular/core/testing';
      import { ServiceDashboardPage } from './service-dashboard.page';
      import { ServiceDashboardService } from '../services/service-dashboard.service';
      import { ServiceAgent } from '../interfaces/service-agent';
      import { of } from 'rxjs';
      describe('ServiceDashboardPage', () => {
          let component: ServiceDashboardPage;
          let fixture: ComponentFixture<ServiceDashboardPage>;
          let serviceDashboardServiceSpy: ServiceDashboardService;
          beforeEach(async(() => {
              serviceDashboardServiceSpy = jasmine.createSpyObj('ServiceDashboardService', 
           ['serviceAgents$']);
              TestBed.configureTestingModule({
                  declarations: [ServiceDashboardPage],
                  schemas: [CUSTOM_ELEMENTS_SCHEMA],
                  providers: [
                      { provide: ServiceDashboardService, useValue: serviceDashboardServiceSpy }
                  ]
              })
              .compileComponents();
          }));
          beforeEach(() => {
              fixture = TestBed.createComponent(ServiceDashboardPage);
              component = fixture.componentInstance;
              fixture.detectChanges();
          });
          it('should create', async(() => {
              (serviceDashboardServiceSpy.serviceAgents$ as unknown as 
           jasmine.Spy).and.returnValue(of([] as ServiceAgent[]));
              expect(component).toBeTruthy();
          }));
      });  

您编写的代码存在许多问题。 正如上面评论中指出的那样,您显然希望服务中有一个 Observable,但是命令:

serviceDashboardServiceSpy = jasmine.createSpyObj('ServiceDashboardService', ['serviceAgents$']);

serviceAgents$创建为 function,而不是 Observable。

但是仅仅改变它不会使你的代码可测试,因为你会想要改变那个 Observable 返回的值并测试你的组件是否对这些改变做出了正确的反应。 为此,您将需要重构您的代码。 重构的原因是因为您通过立即定义组件来设置 Observable 的方式意味着很难更改值并轻松测试。 然而,简单地将分配移动到ngOnInit()将使这更容易测试。

然后,您需要将 fixture.detectChanges( fixture.detectChanges()移出beforeEach()并移入规范本身( it()函数)。 这样做的原因是因为ngOnInit() fixture.detectChanges()将执行我们刚刚设置的 ngOnInit() ,并且我们希望更仔细地控制何时调用它。

Finally, you need to set up something to mock your service class - you were trying to use serviceDashboardServiceSpy object to do so, but in this case I prefer to use a mock class rather than a spy object. 这样做的原因是因为您在实际服务 class 中将serviceAgents$定义为 PROPERTY 而不是 function。 这使得测试变得更加棘手,并且在我看来,设置模拟 class 而不是间谍 object 会使这更容易一些。

考虑到所有这些因素,我设置了这个StackBlitz来显示您的测试通过。

我还添加了一些测试来显示更改服务 Observable 中的值如何更改组件中的关联值。

这是 StackBlitz 的.spec:

class MockServiceDashboardService {
  get serviceAgents$() {
    return of({length: 2});
  }
}

describe('ServiceDashboardPage', () => {
    let component: ServiceDashboardPage;
    let fixture: ComponentFixture<ServiceDashboardPage>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [ServiceDashboardPage],
            schemas: [CUSTOM_ELEMENTS_SCHEMA],
            providers: [
                { provide: ServiceDashboardService, useClass: MockServiceDashboardService }
            ]
        })
        .compileComponents();
    }));
    beforeEach(() => {
        fixture = TestBed.createComponent(ServiceDashboardPage);
        component = fixture.componentInstance;
    });
    it('should create', () => {
      fixture.detectChanges();
      expect(component).toBeTruthy();
    });
    it('should have length of 2', () => {
      fixture.detectChanges();
      expect(component.serviceAgentSlideOptions.slidesPerView).toEqual(2);
    });
    it('should have a length of 3', () => {
      let dService = TestBed.get(ServiceDashboardService);
      spyOnProperty(dService, 'serviceAgents$').and.returnValue(of({length: 3}))
      fixture.detectChanges();
      expect(component.serviceAgentSlideOptions.slidesPerView).toEqual(3);
    });
}); 

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM