具有依赖性的组件的单元测试具有依赖性,错误是什么?

时间:2016-07-11 13:18:33

标签: unit-testing typescript angular jasmine angular2-testing

我有一个恼人的错误,可能由于我的错误,我无法解决。 我有一个简单的组件,它实际上只不过是我的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应注入组件FAILED       错误:没有位置提供商! (TopBarComponent - > UserService - > Router - > Location)       错误:DI例外[......]

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

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

更新 - 更改代码&错误信息

我已经设法通过将我的规范更改为此来阻止此错误:

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();
}

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

这里的堆栈......

2 个答案:

答案 0 :(得分:1)

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

顶部栏组件依赖于UserService。

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

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

让服务:UserService;

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组件的用例。

答案 1 :(得分:0)

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

删除'= new UserService(router,authHttp,http);'来自'let service:UserService = new UserService(router,authHttp,http);'