为 angular 中 router.events.subscribe 的 "ActivationEnd" 事件编写单元测试

Write unit test for "ActivationEnd" event from router.events.subscribe in angular

我需要帮助才能为 router.events.subscribe 编写单元测试。我使用 ActivationEnd 来使用快照对象,它具有我的应用程序所需的属性。路由器中没有其他事件提供这些,所以我必须坚持这个 ActivationEnd。但是我没有得到关于如何模拟这个 snapshot 对象的任何信息。

下面是我的代码片段。

ngOnInit() {
    this.router.events.subscribe(e => {
      if (e instanceof ActivationEnd) {
        this.section = e.snapshot.data.title;
        this.dynamicSubNavLabel = e.snapshot.routeConfig?.data?.label;
      }
    });
  }

你能帮我做些什么来实现这个或任何替代方案的单元测试吗?

此致, 阿尔佩什

我有时会混合使用 jasmine.createSpyObj 和 json 对象,也许这会对您有所帮助:

 const activationEndMock = {
    ...jasmine.createSpyObj(['']),
    snapshot: {
      data: {
        title: 'a title'
      },
      routeConfig: {
        data: {
          label: 'a label'
        }
      }
    }
  }
  const routerMock = {
    ...jasmine.createSpyObj<Router>(['']),
    events: of(activationEndMock)
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      providers: [{ provide: Router, useValue: routerMock }]
    });
    .........
  });

我不确定这是否有效,因为我没有测试它。

比方说,你有这样一个组件:

import { Component, OnInit } from '@angular/core';
import { ActivationEnd, Router } from '@angular/router';

@Component({
  selector: 'app-test-router',
  templateUrl: './test-router.component.html',
  styleUrls: ['./test-router.component.css']
})
export class TestRouterComponent implements OnInit {
  section = '';
  dynamicSubNavLabel = '';
  constructor(private router: Router) { }

  ngOnInit() {
    this.router.events.subscribe(e => {
      if (e instanceof ActivationEnd) {
        this.section = e.snapshot.data.title;
        this.dynamicSubNavLabel = e.snapshot.routeConfig?.data?.label;
      }
    });
  }

}

因为 Router.events 已经是 Subject<Event>。我们可以这样做:

  • 我们将其转换为 Subject<Event>,然后调用 next 发出我们的 custom/mock ActivationEnd 事件。
  • 首先将我们的模拟数据转换为未知,然后转换为 ActivatedRouteSnapshot。
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, ActivationEnd, Event, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { Subject } from 'rxjs';

import { TestRouterComponent } from './test-router.component';

describe('TestRouterComponent', () => {
  let component: TestRouterComponent;
  let fixture: ComponentFixture<TestRouterComponent>;
  let router: Router;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      declarations: [ TestRouterComponent ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(TestRouterComponent);
    component = fixture.componentInstance;
    router = TestBed.inject(Router);
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should update data from router', () => {
    const events$ = router.events as Subject<Event>;
    const mockSnapshot = {
      data: {
        title: 'some heading'
      },
      routeConfig: {
        data: {
          label: 'some text'
        }
      }
    } as unknown as ActivatedRouteSnapshot;
    events$.next(new ActivationEnd(mockSnapshot));
    expect(component.section).toBeTruthy();
    expect(component.dynamicSubNavLabel).toBeTruthy();
  })
});

来自 Angular 的源代码:https://github.com/angular/angular/blob/75a3c778b1f7be913f0287423d40fade68ee9adc/packages/router/src/router.ts#L461