Angular2/ Жасмин впрыскивают ложный сервис, не вызывая шпионов

Попытка провести модульное тестирование приложения angular2 с использованием жасмина, но когда я пытаюсь внедрить службу, шпионы не реагируют на входящие вызовы.

Тестирование:

import { TestBed, inject, tick, fakeAsync, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';

import { RoomComponent } from './room.component';

import { Room } from './room';
import { RoomService } from './room.service';
import { MockRoomService } from '../mock/mock.room.service';
import { BaseRequestOptions, Http, ConnectionBackend, Response, ResponseOptions } from '@angular/http';
import { MockBackend } from '@angular/http/testing';

...

beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
  declarations: [
    RoomComponent
  ],
  providers: [
    {
      provide: Http, useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => {
        return new Http(backend, defaultOptions);
      },
      deps: [MockBackend, BaseRequestOptions]
    },
    RoomService,
    {provide: MockBackend, useClass: MockBackend},
    {provide: BaseRequestOptions, useClass: BaseRequestOptions}
  ],
  imports: [
    RouterTestingModule
  ]
})
.overrideComponent(RoomComponent, {
  set: {
    providers: [{provide: RoomService, useClass: MockRoomService}]
  }
})

...

it('should have rooms after getRooms', inject([RoomService], fakeAsync((mockRoomService: MockRoomService) => {
  let spy = spyOn(mockRoomService, 'getRooms').and.callThrough();
  fixture.detectChanges();
  tick();
  expect(spy).toHaveBeenCalled(); //Does not return true
  expect(component.rooms).toBeDefined();
})));

Проверено, что сами шпионы работают (используя фиктивный сервис и прямой вызов), что они делают, и что компонент вызывает фиктивный сервис, а не реальный, возвращая тестовые данные:

LOG: 'ngInitified'
PhantomJS 2.1.1 (Windows 7 0.0.0): Executed 6 of 21 (skipped 3) SUCCESS (0 secs / 1.156 secs)
LOG: 'method reached'
PhantomJS 2.1.1 (Windows 7 0.0.0): Executed 6 of 21 (skipped 3) SUCCESS (0 secs / 1.156 secs)
LOG: 'mock service reached'
PhantomJS 2.1.1 (Windows 7 0.0.0): Executed 6 of 21 (skipped 3) SUCCESS (0 secs / 1.156 secs)
LOG: [Object{_id: '12', gitrepo: 'repository', channel: 'slack channel'}, Object{_id: '42', gitrepo: 'newrepo', channel: 'dev'}]
PhantomJS 2.1.1 (Windows 7 0.0.0): Executed 6 of 21 (skipped 3) SUCCESS (0 secs / 1.156 secs)
PhantomJS 2.1.1 (Windows 7 0.0.0) Component: Room should have rooms after getRooms FAILED
    Expected spy getRooms to have been called.

Попробовал впрыскивать MockRoomService прямо. Попытка поставить шпиона на объект RoomService вместо фиктивного объекта. Никто не возвращает, что шпион был вызван.

Макет Сервис:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Room } from '../room/room';

@Injectable()
export class MockRoomService {
    testData: Room[] = [{"_id":"12","gitrepo": "repository", "channel": "slack channel"}, {"_id":"42","gitrepo": "newrepo", "channel": "dev"}];

    constructor(http: Http) { }

    getRooms(): Promise<Room[]> {
        console.log("mock service reached");
        return new Promise((resolve, reject) => {
            resolve(this.testData);
        });
    }

...

Реальный Сервис:

import { Room } from './room';
import { Http, Headers, RequestOptions } from '@angular/http';

import 'rxjs/add/operator/toPromise';

import { Injectable } from '@angular/core';

@Injectable()
export class RoomService {
    constructor (private http: Http) {}

    getRooms(): Promise<Room[]> {
        console.log("real service reached");
        return this.http.get('api/rooms/get')
        .toPromise()
        .then(res => res.json() as Room[]);
    }

...

Составная часть:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { Room } from './room';
import { RoomService } from './room.service';

@Component({
  selector: 'app-room',
  templateUrl: './room.component.html',
  styleUrls: ['./room.component.css'],
  providers: [RoomService]
})
export class RoomComponent implements OnInit {
  title = 'Repos and Channels';
  rooms: Room[] = [];
  constructor(
    private roomService: RoomService,
    private router: Router,
    ) {}

  ngOnInit() {
    console.log("ngInitified");
    this.getRooms();
  }

  getRooms() {
    console.log("method reached!");
    this.roomService.getRooms()
      .then(room => { this.rooms = room;
        console.log(this.rooms); }
    );
  }

...

Помогите?

1 ответ

Решение

Вы получаете неправильный экземпляр RoomService поставщик.

it('should have rooms after getRooms', inject([RoomService], fakeAsync((mockRoomService: MockRoomService) => {
  let componentMockRoomService = fixture.debugElement.injector.get(RoomService);
  console.log(mockRoomService instanceof RoomService);         // true
  console.log(componentMockRoomService instanceof RoomService);// false

mockRoomService это экземпляр от корневого провайдера, тогда как вам нужно проверить класс, соответствующий вашему компоненту

так вот ваш тест

let componentMockRoomService = fixture.debugElement.injector.get(RoomService);
let spy = spyOn(componentMockRoomService, 'getRooms').and.callThrough();

Пример плунжера

Другие вопросы по тегам