unit-testing - Angular 2 RC4 : Unit test component that has dependency injection a service that has its own

标签 unit-testing typescript dependency-injection angular jasmine

由于 Angular 团队不断升级/弃用 Angular 2 RC 版本中的内容,我遇到了这个问题。

我有一个具有依赖注入(inject) (DI) 的组件,它实际上是一个服务(在本例中为 UserService)。这个 UserService 当然有它自己的一些 DI。更新到 Angular 2 的最新 RC4 后,我意识到我无法再创建类似的测试。

因为文档没有提到相关的东西,所以这是我的代码(针对这个问题进行了简化)。

我的组件:

import { Component } from '@angular/core';
import { MdButton } from '@angular2-material/button';
import {
  MdIcon,
  MdIconRegistry
} from '@angular2-material/icon';
import { UserService } from '../../services/index';

@Component({
  moduleId: module.id,
  selector: 'logout-button',
  templateUrl: 'logout-button.component.html',
  styleUrls: ['logout-button.component.css'],
  providers: [MdIconRegistry, UserService],
  directives: [MdButton, MdIcon]
})
export class LogoutButtonComponent {

  constructor(public userService: UserService) {}

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

}

Component 的 DI,UserService,如您所见,它有一些 DI(Router、AuthHttp 和 Http):

import { Injectable } from '@angular/core';
import {
  Http,
  Headers
} from '@angular/http';
import {
  AuthHttp,
  JwtHelper
} from 'angular2-jwt';
import { Router } from '@angular/router';
import { UMS } from '../common/index';

@Injectable()
export class UserService {

  constructor(
    private router: Router,
    private authHttp: AuthHttp,
    private http: Http) {

      this.router = router;
      this.authHttp = authHttp;
      this.http = http;
    }

    /**
     * Logs out user
     */
    public logout() {
      this.authHttp.get(UMS.url + UMS.apis.logout)
      .subscribe(
        data => this.logoutSuccess(),
        err => this.logoutSuccess()
      );
    }

}

下面是组件的测试:

import { By }           from '@angular/platform-browser';
import { DebugElement } from '@angular/core';

import {
  beforeEach,
  beforeEachProviders,
  describe,
  expect,
  it,
  inject,
  fakeAsync,
  TestComponentBuilder
} from '@angular/core/testing';

import { AuthHttp } from 'angular2-jwt';
import { Router } from '@angular/router';
import { Http } from '@angular/http';
import { LogoutButtonComponent } from './logout-button.component';
import { UserService } from '../../services/index';

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



  beforeEachProviders(() => [
    LogoutButtonComponent,
    UserService
  ]);

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

});

暂时不要担心(它)。

如您所见,我正在 beforeEachProviders 上添加相关的提供程序。

在这种情况下,我在运行测试时遇到错误:

Error: No provider for Router! (LogoutButtonComponent -> UserService -> Router)

比方说这是预期的。

因此,为了避免出现这些错误,我还在提供程序中添加了服务的 DI:

  beforeEachProviders(() => [
    LogoutButtonComponent,
    Router,
    AuthHttp,
    Http,
    UserService
  ]);

但现在我收到了这个错误:

Error: Cannot resolve all parameters for 'Router'(?, ?, ?, ?, ?, ?, ?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'Router' is decorated with Injectable.

我真的很想弄清楚发生了什么,所以我在这里找到了一些相关的答案,但所有答案都已过时并涵盖了旧的 router-deprecatedangular2/router 但是两者都已弃用,并且不涵盖这种情况。

会喜欢这方面的一些帮助,也许还有一些资源,因为我找不到与路由器最新版本相关的任何内容:"@angular/router": "3.0.0-beta.2",和 RC4

谢谢

更新!

我设法绕过了上面的两个错误,现在我可以访问该组件了。这是描述代码:

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

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

  beforeEachProviders(() => [
    LogoutButtonComponent
  ]);

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

  it('should inject UserService', () => {
    expect(component.userService).toBeTruthy();
  });

  it('should logout user', () => {
    localStorage.setItem('token', 'FOO');
    component.logout();
    expect(localStorage.getItem('token')).toBeUndefined();
  });

});

但似乎即使 DI 服务已注入(inject)并可访问,服务的 DI 也不是。所以现在我得到这个错误:

TypeError: this.authHttp.get is not a function

有什么想法吗?

最佳答案

看起来您遇到了依赖循环问题,因为您的 UserSerivce 还需要注入(inject) AuthHttp、Http 等...如果您需要测试您的组件,它真的会被打扰一次。 我的方法是创建一个模拟 UserSerivce 并通过 UserService.logout() 方法返回期望的模拟值,因为您不必知道 UserService 中到底发生了什么,您需要的只是一个返回值:

let MockUserService = {
  logout() {
    // return some value you need 
  }
}

然后,在测试套件中:

import { provide } from '@angular/core'

beforeEachProviders(() => [
  provide(UserService, {useClass: MockUserService})
])

... detail test code here

我希望这对你有用。 这是一篇对我有很大帮助的帖子: https://developers.livechatinc.com/blog/testing-angular-2-apps-dependency-injection-and-components/

关于unit-testing - Angular 2 RC4 : Unit test component that has dependency injection a service that has its own,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38397245/

相关文章:

ios - CocoaPod 和 Swift 框架的单元测试

typescript :onPress 类型

typescript - Angular 2 : How to know number of iterators on *ngFor

dependency-injection - 安全地重新初始化 DI 容器中的 "single instance"依赖项

c# - 创建使用控制反转的对象

unit-testing - 如何在 tdd 中重构测试?

javascript - 仅使用 ngOnInit 函数测试简单的 Angular 组件

ios - Swinject:使用弱作用域会泄漏对象

unit-testing - 如何在 TFS 中使用起订量

javascript - 将 Typescript 编译为 javascript 时包括严格类型