How to spy a service call in Angular2

The other solutions didn't work for me so I injected the service with injector from debugElement.

import { TestBed, 
         async }  from '@angular/core/testing';

@injectable()
class MyService {
  public method () {}
}

let MyMockedService = {
  method: () => {}
}

@Component({
  template: ''
})
class MyComponent {
  constructor(private myService: MyService) {;}
  public method () {
    this.myService.method();
  }
}

describe('Test', () => {
  beforeEach(async(() => {
    TestBed
      .configureTestingModule({
        imports: [
          CommonModule
        ],
        declarations: [
          MyComponent
        ],
          providers: [
            { provide: MyService, useValue: MyMockedService}
        ]
      })
      .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(MyComponent);
        myComponent = fixture.componentInstance;
      });
  }));
  it('should spy on service', () => {
    let myMockedService = fixture.debugElement.injector.get(MyMockedService);
    spyOn(myMockedService, 'method');
    myComponent.method();
    expect(myMockedService.method);
  });
})

For all the newbies to testing in angular 2 (same as me here)

The createSpy or SpyOn Methods are only 'available' if you have the correct typings for jasmine installed. Otherwise it will throw you a typescript error.

check in your typings.json file and if not present, run this

typings install --save --global registry:dt/jasmine


I take a slightly different approach and use inject itself to get hold of the service instance through DI instead. So your test would look like:

import {
  describe, 
  expect, 
  it,
  tick,
  inject,
  fakeAsync,
  TestComponentBuilder,
  ComponentFixture,
  addProviders
} from 'angular2/testing';

import { Component, provide } from '@angular/core';

import {UserListComponent} from './user-list.component';

import {UserService} from './user.service';
import {MockUserService} from './user.service.mock';

describe('When loading the UserListComponent', () => {

  beforeEach(() => addProviders([
      {provide: UserService, useClass: MockUserService}
  ]));

  it('should call the getAllUsers method from the UserService', 
    inject([TestComponentBuilder, UserService], fakeAsync((tcb: TestComponentBuilder, mockUserService: UserService) => {
      spyOn(mockUserService, 'getAllUsers');

      tcb
        .createAsync(UserListComponent)
        .then((fixture: ComponentFixture) => {
          tick();
          fixture.detectChanges();
          expect(mockUserService.getAllUsers).toHaveBeenCalled();
        });
    }))
  );

  it('should show one mocked user', 
    inject([TestComponentBuilder, UserService], fakeAsync((tcb: TestComponentBuilder, mockUserService: UserService) => {
      mockUserService.setResponse([{
        username: 'ryan',
        email: '[email protected]'
      }]);

      tcb
        .createAsync(UserListComponent)
        .then((fixture: ComponentFixture) => {
          tick();
          fixture.detectChanges();
          let compiled = fixture.debugElement.nativeElement;
          expect(compiled.querySelector('div:nth-child(1) .username')).toHaveText('Username: ryan');
          expect(compiled.querySelector('div:nth-child(1) .email')).toHaveText('Email: [email protected]');
        });
    }))
  );

});

Edit for Angular 4

The latest docs have a simpler way of getting hold of a service using the component's injector:

  fixture = TestBed.createComponent(TestComponent);
  component = fixture.componentInstance;
  const mockService = fixture.debugElement.injector.get(MyService);

Edit for Angular 5+

  import { Component, Injector, Type } from '@angular/core';
  ...

  fixture = TestBed.createComponent(TestComponent);
  component = fixture.componentInstance;
  const mockService = fixture.debugElement.injector.get<MyService>(MyService as Type<MyService>);