Копирование пользовательских сервисов в angular2 во время unit test

Я пытаюсь написать unit test для компонента, используемого в моей службе. Компонент и обслуживание работают нормально.

компонент:

import {Component} from '@angular/core';
import {PonyService} from '../../services';
import {Pony} from "../../models/pony.model";
@Component({
  selector: 'el-ponies',
  templateUrl: 'ponies.component.html',
  providers: [PonyService]
})
export class PoniesComponent {
  ponies: Array<Pony>;
  constructor(private ponyService: PonyService) {
    this.ponies = this.ponyService.getPonies(2);
  }
  refreshPonies() {
    this.ponies = this.ponyService.getPonies(3);
  }
}

Услуги:

import {Injectable} from "@angular/core";
import {Http} from "@angular/http";
import {Pony} from "../../models/pony.model";
@Injectable()
export class PonyService {
  constructor(private http: Http) {}
  getPonies(count: number): Array<Pony> {
    let toReturn: Array<Pony> = [];
    this.http.get('http://localhost:8080/js-backend/ponies')
    .subscribe(response => {
      response.json().forEach((tmp: Pony)=> { toReturn.push(tmp); });
      if (count && count % 2 === 0) { toReturn.splice(0, count); } 
      else { toReturn.splice(count); }
    });
    return toReturn;
  }}

Компонент unit test:

import {TestBed} from "@angular/core/testing";
import {PoniesComponent} from "./ponies.component";
import {PonyComponent} from "../pony/pony.component";
import {PonyService} from "../../services";
import {Pony} from "../../models/pony.model";
describe('Ponies component test', () => {
  let poniesComponent: PoniesComponent;
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [PoniesComponent, PonyComponent],
      providers: [{provide: PonyService, useClass: MockPonyService}]
    });
    poniesComponent = TestBed.createComponent(PoniesComponent).componentInstance;
  });
  it('should instantiate component', () => {
    expect(poniesComponent instanceof PoniesComponent).toBe(true, 'should create PoniesComponent');
  });
});

class MockPonyService {
  getPonies(count: number): Array<Pony> {
    let toReturn: Array<Pony> = [];
    if (count === 2) {
      toReturn.push(new Pony('Rainbow Dash', 'green'));
      toReturn.push(new Pony('Pinkie Pie', 'orange'));
    }
    if (count === 3) {
      toReturn.push(new Pony('Fluttershy', 'blue'));
      toReturn.push(new Pony('Rarity', 'purple'));
      toReturn.push(new Pony('Applejack', 'yellow'));
    }
    return toReturn;
  };
}

Часть пакета package.json:

{
  ...
  "dependencies": {
    "@angular/core": "2.0.0",
    "@angular/http": "2.0.0",
    ...
  },
  "devDependencies": {
    "jasmine-core": "2.4.1",
    "karma": "1.2.0",
    "karma-jasmine": "1.0.2",
    "karma-phantomjs-launcher": "1.0.2",
    "phantomjs-prebuilt": "2.1.7",
    ...
  }
}

Когда я запускаю "начало кармы", я получаю эту ошибку

Ошибка: ошибка. /PoniesComponent class PoniesComponent_Host - встроенный шаблон: 0: 0, вызванный: Нет провайдера Http! в config/karma-test-shim.js

Похоже, что карма использует PonyService вместо того, чтобы издеваться над ней как MockPonyService, несмотря на эту строку: providers: [{provide: PonyService, useClass: MockPonyService}].

Вопрос: как я должен издеваться над сервисом?

Ответ 1

Из-за этого

@Component({
  providers: [PonyService]  <======
})

Это делает так, чтобы служба была привязана к компоненту, а это означает, что Angular создаст ее для каждого компонента, а также означает, что она отменяет любые глобальные поставщики, настроенные на уровне модуля. Это включает в себя макет поставщика, который вы настраиваете на тестовом поле.

Чтобы обойти это, Angular предоставляет метод TestBed.overrideComponent, который позволяет нам переопределять такие вещи, как @Component.providers и @Component.template.

TestBed.configureTestingModule({
  declarations: [PoniesComponent, PonyComponent]
})
.overrideComponent(PoniesComponent, {
  set: {
    providers: [
      {provide: PonyService, useClass: MockPonyService}
    ]
  }
});