Единичное тестирование spyOn наблюдаемое обслуживание в angular2

У меня есть служба (ChildService), которая зависит от другой службы (InteractWithServerService). Последний сервис (InteractWithServerService) используется для выполнения серверных вызовов и возврата наблюдаемого типа "любой". Для простоты предположим, что он возвращает наблюдаемую. Я пытаюсь написать unit тест для ChildService.

ChildService

@Injectable()
export class ApplicationService {
    constructor(private  interactWithServerService:InteractWithServerService){;}

    public GetMeData():string {
        var output:string;       
        this.interactWithServerService.get("api/getSomeData").
           subscribe(response =>{console.log("server response:", response);
           output=response});        
         return output;
    }
}

ServerInteractionService

@Injectable()
export class InteractWithServerService {        
    constructor(private http: Http) {
        ;
    }    
    get(url: string): Observable<any> {        
        return this.http.get(this.url);
    }       
}

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

class MockInteractWithServerService {
    get() {
        return Observable.of("some text");
    }           
}

describe('Service:ChildService', () => {
    let childService: ChildService;

    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [
             { provide: InteractWithServerService, useClass: MockInteractWithServerService },
                ChildService],
        });


    beforeEach(inject([ChildService], (actualService: ChildService) => {
        childService= actualService;        
    }));

    fit('should call server-call testCall()', () => {
        let actualReturnvalue= childService.GetMeData();        
        expect(actualReturnvalue).toBe("some text");
    });
});

Приведенный выше метод не является предпочтительным, так как я мог бы в итоге написать "n" фиктивных классов для "n" зависимостей. Поэтому я хочу создать свои модульные тесты, используя spyOn. Тем не менее, контрольный пример не работает и выдает "Ошибка: Нет поставщика для Http!". Хотя я понимаю, что это за ошибка, я хотел бы знать, почему она появляется, хотя я шпионю за зависимым сервисом. Похоже, "SpyOn" не работает.

describe('Service:ChildService', () => {
    let childService: ChildService;

    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [
             InteractWithServerService,
                ChildService],
        });

        spyOn(InteractWithServerService.prototype, 'get').and
             .callFake(()=>      
          {return Observable.of("some text");});       
    });
    beforeEach(inject([ChildService], (actualService: ChildService) => {
        childService= actualService;        
    }));

    fit('should call server-call testCall()', () => {
        let actualReturnvalue= childService.GetMeData();        
        expect(actualReturnvalue).toBe("some text");
    });
});

Я что-то упускаю из виду?

Ответ 1

Однако тестовый пример не работает и выбрасывает "Ошибка: нет провайдера для Http!".

Поскольку у вас все еще есть служба в providers, поэтому Angular пытается ее создать

providers: [
 InteractWithServerService,
    ChildService],

Что вы можете сделать вместо создания класса mock, просто выполните что-то вроде

providers: [
  { 
    provide: InteractWithServerService,
    useValue: { get: Observable.of(..) }
  }
]

Здесь вы используете useValue, которые предоставляют любой объект. Это будет значение, используемое при введении. В приведенном выше примере это просто какой-то произвольный объект с вашим макетным методом.

Если вы хотите следить за тем, чтобы вы могли предоставить разные значения, вы можете ввести InteractWithServerService, а затем сделать

spyOn(service, 'get').and.returnValue(Observable.of(...))
// do test

Еще одна вещь, которую вы могли бы сделать, - обмануть Http с помощью фиктивного объекта

{ provide: Http, useValue: {} }

Теперь будет работать InteractWithServerService (просто добавив класс к провайдерам, как у вас в настоящее время). И вы можете просто шпионить за ней.

let service = TestBed.get(InteractWithServerService);
spyOn(service, 'get').and.returnValue(..)
// do test

Ответ 2

Использование jasming 2.6.2: get - это функция, поэтому вам нужно добавить обозначение функции стрелки к ответу выше:

providers: [
  { 
    provide: InteractWithServerService,
    useValue: { get: () => Observable.of(..) }
  }
]