Angular 4单元测试错误 "TypeError: Cannot read property '订阅'未定义”

标签 angular unit-testing jasmine karma-jasmine

在对 Angular 4 组件进行单元测试时,我陷入困境并不断出错。

这是我的组件:

order-detail.component.ts

@Component({
  selector: 'order-detail',
  templateUrl: 'order-detail.component.html',
  providers: [OrderService]
})
export class OrderDetailComponent implements OnInit {
  private order: Order;

  constructor(
    private orderService: OrderService,
    private route: ActivatedRoute,
    private router: Router
  ) {}

  ngOnInit() {
    this.getOrder();
  }

  private getOrder(): void {
    this.route.paramMap
      .map((params: ParamMap) => {
        if (+params.get('id') === 0) {
          this.router.navigateByUrl('/404', {skipLocationChange: true});
        }

        return params;
      })
      .switchMap((params: ParamMap) => this.orderService.getOrder(+params.get('id')))
      .subscribe((order: Order) => this.order = order);
  }
}

这是一项服务:

order.service.ts

@Injectable()
export class OrderService {
  private ordersUrl = `${environment.apiUrl}/orders/`;

  constructor(private http: HttpClient) {}

  getOrder(id: number): Observable<Order> {
    return this.http.get(`${this.ordersUrl}${id}/`)
      .map(response => response as Order);
  }
}

我想在 OrderServive 上设置一个 spy 并使用这样的测试对其进行单元测试:

order-detail.component.spec.ts

describe('Order detail component', () => {
  let fixture: ComponentFixture<OrderDetailComponent>;
  let page: Page;
  let activatedRoute: ActivatedRouteStub;
  const fakeOrder: Order = {
    id: 1,
    title: 'Test 1',
    contractor: {title: 'Contractor 1'} as Contractor,
  } as Order;

  class Page {
    orderSpy: jasmine.Spy;
    routerSpy: jasmine.Spy;
    title: HTMLElement;

    constructor() {
      const orderService = fixture.debugElement.injector.get(OrderService);
      this.orderSpy = spyOn(orderService, 'getOrder').and.returnValue(Observable.of(fakeOrder));
    }
  }

  function createComponent() {
    fixture = TestBed.createComponent(OrderDetailComponent);
    page = new Page();

    fixture.detectChanges();

    return fixture.whenStable().then(() => {
      fixture.detectChanges();
    });
  }

  beforeEach(() => {
    activatedRoute = new ActivatedRouteStub();
  });

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [OrderDetailComponent],
      imports: [RouterTestingModule, HttpClientTestingModule],
      providers: [
        OrderService,
        {provide: ActivatedRoute, useValue: activatedRoute},
        {provide: Router, useClass: RouterStub},
      ],
      schemas: [NO_ERRORS_SCHEMA],
    }).compileComponents();
  }));

  describe('when navigate with existing id', () => {
    beforeEach(async(() => {
      activatedRoute.testParamMap = {id: fakeOrder.id};
      createComponent();
    }));

    it('should show title', () => {
      expect(page.orderSpy).toHaveBeenCalledWith(fakeOrder.id);
    });
  });

});

但我不断收到此错误:TypeError:无法读取未定义的属性“订阅”

我从 Agular 文档中获取了 ActivatedRouteStub 和测试结构:https://angular.io/guide/testing

组件的代码可以很好地处理来自后端的真实数据并显示顺序。

我的代码库也包含类似的测试,它在具有类似服务的另一个组件上成功执行了相同的操作,因此该测试是唯一失败的地方。

使用 Angular 4.3.6、Karma 1.7.1 和 Jasmine 2.6.4。

可能会出现什么问题以及如何消除此错误?

最佳答案

经过一番研究,我实际上找出了导致错误的原因。我删除了

{provide: Router, useClass: RouterStub},

错误消失了。测试现在可以在没有此 stub 的情况下完美运行。

不确定问题是什么,但我认为文档中的 RouterStub 类缺少一些必要内容的实现。类(class)是从这里获取的:

https://angular.io/guide/testing#test-a-routed-component

https://angular.io/generated/live-examples/testing/app-specs.eplnkr.html

关于Angular 4单元测试错误 "TypeError: Cannot read property '订阅'未定义”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46062481/

相关文章:

angular - 在 TestBed 模块中创建时,NGRX 和 NGXS 会创建单独的 Store 实例吗?

Angular 8 单元测试,无法设置 null 的属性 'valueAccessor'

Angular Testing 路由器参数破坏测试台

javascript - 无法绑定(bind)到 'images',因为安装后它不是 'angular-image-slider' 的已知属性

javascript - 使用 jasmine 模拟函数调用

unit-testing - 如何在单元测试期间使用 vue-test-utils 和 jest 模拟 mixin?

swift - 如何使用 UI 单元测试获取嵌入式框架的 Xcode 8 代码覆盖率

如果为空,Angular2 隐藏输出

javascript - Angular 2+ 计时器功能在其中一个组件中不起作用

Angular 4 : Mock ElementRef