【问题标题】:Angular2 + Jasmine: Testing Router EventsAngular2 + Jasmine:测试路由器事件
【发布时间】:2019-04-30 10:44:26
【问题描述】:

有人可以帮助我了解如何对下面的应用组件进行单元测试吗?这是一个 Angular 2 应用程序。

app.ts

import { Component, OnInit }     from '@angular/core';
import { Router, NavigationEnd, NavigationStart, NavigationCancel, NavigationError, RoutesRecognized } from '@angular/router';

import { DataService }           from '../services/data';

@Component({
  selector: 'app',
  template: '<messages></messages><router-outlet></router-outlet>',
  providers: [DataService]
})
export class AppComponent implements OnInit {

  constructor(private router: Router, private data: DataService) {}

  public ngOnInit(): void {
    this.router.events.subscribe((event: NavigationStart | NavigationEnd | NavigationCancel | NavigationError | RoutesRecognized) => {
        if (!(event instanceof NavigationEnd)) { return; }

        document.body.scrollTop = 0;
    });

    window.addEventListener(
        "offline", () => {
            if (this.data.settings.offlineEnabled) {
                this.data.toggleOffline();
                this.data.displayMessage("Internet connection lost, switching to offline mode.", "failure")
            } else {
                this.data.displayMessage("Internet connection lost", "failure")
            }
        }, false,
      );
  }
}

到目前为止我得到了什么:

app.spec.ts

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { AppComponent } from './app'

import { RouterTestingModule } from '@angular/router/testing';
import { MessagesComponent } from './messages/messages';

import { DataService }           from '../services/data';

/* Tests */
export class MockDataService {}

describe('Component: App', () => {
  let mockData = new MockDataService();
  let component: AppComponent;
  let dataService: DataService;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        AppComponent,
        MessagesComponent
      ],
      providers: [
        { provide: DataService, useValue: mockData }
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    dataService = TestBed.get(DataService);
  }));

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

});

我收到错误: Failed: No provider for e! 但是,在我看来,我正在导入 组件实例化所需的所有内容。

我想知道这是不是 1) RouterTestingModule 不知道 router.events.subscribe;或者,2) window 未定义。

有什么想法吗?

谢谢!

编辑 1:

似乎导致我的问题的行是这样的:

@Component({
  ...,
  ...,
  providers: [DataService]
})

Jasmine 似乎将MockDataService 对象注入app.component 构造函数,但它没有为提供者注入对象。 Jasmine 正在提供具体的 DataService 实现。

如何将MockDataService 注入app.component 的提供程序?

【问题讨论】:

  • 我无法具体说明您的错误,但这里的答案:stackoverflow.com/a/52347301/1433116 应该可以帮助您获得更好的诊断信息
  • 很遗憾,原来的开发者没有使用 CLI。

标签: angular typescript jasmine


【解决方案1】:

您的问题可能是因为您还在单元测试中声明了 MessagesComponent。 Angular 将尝试新建一个此类的实例,如果您还没有为 MessagesComponent 使用的服务注入模拟,那么这可能会导致您的错误。

但是,由于您正在对 AppComponent 进行单元测试,因此您不希望将 MessagesComponent 添加到您的声明中,因为正如您所经历的那样,一切似乎都在您的 AppComponent 中工作,但是您的组件的依赖关系导致您的测试失败。解决此问题的最简单方法是将 NO_ERRORS_SCHEMA 添加到您的 TestingModule 中,如下所示:

TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        AppComponent
      ],
      providers: [
        { provide: DataService, useValue: mockData }
      ],
      schemas: [
        NO_ERRORS_SCHEMA
      ]
    }).compileComponents();

这将防止 Angular 编译器抱怨代码中的自定义 HTML 标记,如标记。

【讨论】:

  • 我找到了更多信息。请查看问题的编辑
  • 啊,我明白了。您之前的方式是正确的,但是因为您将服务注入组件的提供程序而不是 app.module.ts 组件中的提供程序优先于您在全球范围内声明的任何内容,这就是您正在做的事情你的配置测试模块。这应该阐明如何模拟组件中提供的服务。 (stackoverflow.com/q/40021366/10414411)
  • 就是这样。我新的组件范围提供程序优先于全局提供程序......我只是不知道如何注入它们。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-01
  • 2012-04-19
  • 1970-01-01
相关资源
最近更新 更多