4

我有恼人的错误,可能由于我的错误我无法解决。我有一个简单的组件,它实际上只是我的 Web 应用程序中的顶栏元素。

如您所见,该组件只有一个依赖项,UserService并且它非常简单地使用它:

import { Component, OnInit } from '@angular/core';
import { MdButton } from '@angular2-material/button';
import { MdIcon , MdIconRegistry} from '@angular2-material/icon';
import { UserService } from '../services/index';
import { RouteConfig, ROUTER_DIRECTIVES, Router, ROUTER_PROVIDERS 
  } from '@angular/router-deprecated';


@Component({
  moduleId: module.id,
  selector: 'top-bar',
  templateUrl: 'top-bar.component.html',
  styleUrls: ['top-bar.component.css'],
  providers: [MdIconRegistry, UserService, ROUTER_PROVIDERS],
  directives: [MdButton, MdIcon, ROUTER_DIRECTIVES]
})
export class TopBarComponent implements OnInit {

  constructor(private userService: UserService) {
    this.userService = userService;
  }

  ngOnInit() {
  }

  /**
   * Call UserService and logout() method
   */
  logout() {
    this.userService.logout();
  }

}

由于该服务还具有一些依赖项(路由器等),因此我必须在beforeEachProviders方法中提供它们,如您所见:

import {
  beforeEach,
  beforeEachProviders,
  describe,
  expect,
  it,
  inject,
} from '@angular/core/testing';
import { TopBarComponent } from './top-bar.component';
import {
  Router, RootRouter, RouteRegistry, ROUTER_PRIMARY_COMPONENT
} from '@angular/router-deprecated';
import { provide } from '@angular/core';
import { SpyLocation } from '@angular/common/testing';
import { UserService } from '../services/index';

describe('Component: TopBar', () => {

  beforeEachProviders(() => [
      RouteRegistry,
      provide(Location, { useClass: SpyLocation }),
      provide(ROUTER_PRIMARY_COMPONENT, { useValue: TopBarComponent }),
      provide(Router, { useClass: RootRouter }),
      UserService,
      TopBarComponent
  ]);

  it('should inject the component', inject([TopBarComponent],
      (component: TopBarComponent) => {
    expect(component).toBeTruthy();
  }));

});

当我运行测试时,虽然我收到此错误消息:

Chrome 51.0.2704 (Mac OS X 10.11.5) 组件:TopBar 应该注入组件失败错误:没有位置提供程序!(TopBarComponent -> UserService -> 路由器 -> 位置)错误:DI 异常 [......]

首先,您可以看到提供了位置提供程序。其次,为什么我的测试需要提供(或注入)所用组件服务的依赖项?

例如,如果从上面的测试中我删除了路由器,即使我的组件不使用路由器,我也会得到一个错误,因为使用的服务使用了。那么我不应该在组件中收到相同的错误,而不仅仅是在测试中吗?

更新 - 更改代码和错误消息

我已经设法通过将我的规范更改为这样来停止出现此错误:

import {
  beforeEach,
  describe,
  expect,
  it,
} from '@angular/core/testing';
import { TopBarComponent } from './top-bar.component';
import { UserService } from '../services/index';
import {
  Router
} from '@angular/router-deprecated';
import { Http } from '@angular/http';
import { AuthHttp } from 'angular2-jwt';

describe('Component: TopBar', () => {

  let router: any = Router;
  let authHttp: any = AuthHttp;
  let http: any = Http;
  let component: TopBarComponent;
  let service: UserService = new UserService(router, authHttp, http);

  beforeEach(() => {
      component = new TopBarComponent(service);
  });

  it('logout function should work ', () => {
    let logout = component.logout;
    logout();
    expect(localStorage.getItem('token')).toBe(null);
  });

});

但是知道我从我的组件中得到了这个错误:

TypeError:无法读取未定义的属性“userService”

提到的错误在这个函数上:

logout() {
  this.userService.logout();
}

我的组件,但这只是在测试中。在应用程序中它可以正常工作。在我的测试中,由于某种原因,该函数无法到达构造函数的参数。

这里的堆栈...

4

2 回答 2

3

通过您的代码,我了解到您正在尝试测试 topbar 组件。

顶栏组件依赖于 UserService。

因此,为了回答您的问题,Angular 在您运行应用程序时会进行依赖注入,因为所有提供程序都在模块文件中进行了配置。但是,当您尝试测试规范文件中的代码时,您必须使用所有提供程序配置测试平台,将要使用的 beforeEach 方法中的组件和 Angular 将解决依赖关系的所有责任留给用户,因为测试平台充当环境运行您的代码。

在您的代码中,您可以执行以下操作

让服务:用户服务;

beforeEach(() => {
  TestBed.configureTestingModule({ 
    providers: [UserService, any other service on which user service is dependent] });
});

在这里您可以看到 TestBed.configureTestingModule 方法创建了一个虚拟模块来帮助运行您的测试用例。

我的建议是创建一个模拟 UserService ,它没有像原始依赖项那样的任何其他依赖项,并将其分配给提供程序

像这样的东西

export MockUserService {
  Put all essential methods stub here.
}

let service: UserService;

beforeEach(() => {
  TestBed.configureTestingModule({ 
    providers: [provide: UserService, useClass: MockUserService] });
});

然后只需测试 topBar 组件的用例。

于 2018-06-24T03:16:26.310 回答
0

尝试使用 TestBed.get(UserService) 在 beforeEach 中创建服务对象。此代码将自动解析依赖项并创建该对象以供使用。

删除 '= new UserService(router, authHttp, http);' 来自'让服务:UserService = new UserService(router, authHttp, http);'

于 2018-03-01T05:44:47.567 回答