使用 Router.events Angular 9 进行单元测试

时间:2021-05-24 10:26:27

标签: angular typescript unit-testing

我是 Angular 和单元测试的新手,现在我找不到一种方法来测试下面这个服务中的代码。这负责创建面包屑菜单。在路由模块中,我为每条路由添加了 --> data:{breadcrumb:'custom name'}。

这是服务代码:

import {Injectable} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
import {IBreadcrumbs} from '../breadcrumb/ibreadcrumbs';
import {ActivatedRouteSnapshot, Data, NavigationEnd, Router} from '@angular/router';
import {filter} from 'rxjs/operators';


@Injectable({
  providedIn: 'root'
})
export class BreadcrumbService {

  /// Subject emitting the breadcrumb hierarchy
  private readonly breadcrumbsSub$ = new BehaviorSubject<IBreadcrumbs[]>([]);

  // Observable exposing the breadcrumb hierarchy
  readonly breadcrumbs$ = this.breadcrumbsSub$.asObservable();

  constructor(private router: Router) {
    this.router.events
      .pipe(
        // Filter the NavigationEnd events as the breadcrumb is updated only when the route reaches its end
        filter((event) => event instanceof NavigationEnd)
      )
      .subscribe((event) => {
        // Construct the breadcrumb hierarchy
        const root = this.router.routerState.snapshot.root;
        const breadcrumbs: IBreadcrumbs[] = [];


        this.addBreadcrumb(root, breadcrumbs);
        // Emit the new hierarchy
        this.breadcrumbsSub$.next(breadcrumbs);
      });
  }


  private addBreadcrumb(
    route: ActivatedRouteSnapshot | null,
    breadcrumbs: IBreadcrumbs[]
  ) {
    if (route) {
      // Add an element for the current route part
      if (route.data.breadcrumb) {
        const breadcrumb = {
          label: this.getLabel(route.data),
          url: route.url.toString()
        };
        breadcrumbs.push(breadcrumb);
      }
      // Add another element for the next route part
      this.addBreadcrumb(route.firstChild, breadcrumbs);
    }
  }

  private getLabel(data: Data) {
    // The breadcrumb can be defined as a static string or as a function to construct the breadcrumb element out of the route data
    return typeof data.breadcrumb === 'function'
      ? data.breadcrumb(data)
      : data.breadcrumb;
  }


}

这是我的 spec.ts 文件

import {TestBed} from '@angular/core/testing';

import {BreadcrumbService} from './breadcrumb.service';
import {RouterTestingModule} from '@angular/router/testing';
import {Router, RouterEvent} from '@angular/router';
import {ReplaySubject} from 'rxjs';


fdescribe('BreadcrumbService', () => {
  let service: BreadcrumbService;
  let routerEventRelaySubject: ReplaySubject<RouterEvent>;
  let routerMock;
  let router: Router;


  beforeEach(() => {
    routerEventRelaySubject = new ReplaySubject<RouterEvent>(1);
    routerMock = {
      events: routerEventRelaySubject.asObservable()
    };
    TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      providers: [{provide: Router, useValue: routerMock}]
    });
    service = TestBed.inject(BreadcrumbService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

});

我需要至少 80% 的覆盖率,请帮助我实现这一目标。 提前致谢。

2 个答案:

答案 0 :(得分:0)

如果您想了解如何在 Angular 中测试路由,这里有一篇很好的文章:Testing Angular routing components with the RouterTestingModule。我预见的唯一警告是 this.router.routerState.snapshot 的使用。 RouterTestingModule 可能不会对其进行评估。您可能需要像使用 events 一样模拟它。

我想提供一个完整的解决方案太令人期待了。因此,理解文章并自己动手做将是一个不错的方法。

答案 1 :(得分:0)

请在发布问题前展示您之前的尝试。如果您不熟悉单元测试,则对空 BreadcrumbService 进行测试可能会有所帮助。然后,您可以为构造函数添加另一个测试。由于您同时使用 Angular 路由器和 rxjs 运算符,因此查看他们的文档以了解如何在其框架中进行模拟/测试会很有用。

底线:做一个简单的小测试,通过,添加功能,然后重复。

相关问题