当前位置: 动力学知识库 > 问答 > 编程问答 >

unit testing spyOn observable service in angular2

问题描述:

I am having a service (ChildService) which depends on another service (InteractWithServerService ). Later service (InteractWithServerService ) is used to make server calls and return an observable of "any" type. For simplicity, lets assume it returns observable. I am trying to write unit test for 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);

}

}

The test case works fine when I mock the dependent service. i.e.,

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");

});

});

The above method is not the preferred as I might end up writing "n" mock classes for "n" dependencies. So I want to create my unit tests using spyOn.

However, the test case doesn't work and throws "Error: No provider for Http!". While I understand what the error is, I would like to know why it is thrown although I am spying on the dependent service. Looks like the "spyOn" is not working.

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");

});

});

Am I missing something obvious?

网友答案:

However, the test case doesn't work and throws "Error: No provider for Http!".

Because you still have the service in the providers, so Angular is trying to create it still

providers: [
 InteractWithServerService,
    ChildService],

What you can do instead of creating a mock class is to just do something like

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

Here's you're using useValue which provide any object. That will be the value used when injected. In the case above, it is just some arbitrary object with your mock method.

If you want to spy so that you can provide different values, you could inject the InteractWithServerService, and then do

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

Another thing you could do is mock the Http with a dummy object

{ provide: Http, useValue: {} }

Now the InteractWithServerService will work (just adding the class to the providers` like you currently have). And you can just spy on it

let service = TestBed.get(InteractWithServerService);
spyOn(service, 'get').and.returnValue(..)
// do test
分享给朋友:
您可能感兴趣的文章:
随机阅读: