Website-Suche

angular - Unit-Testing spyOn Observable-Service in Angular2


Ich habe einen Dienst (ChildService), der von einem anderen Dienst (InteractWithServerService) abhängt. Der letztere Dienst (InteractWithServerService) wird verwendet, um Serveraufrufe zu tätigen und ein Observable vom Typ "any" zurückzugeben. Der Einfachheit halber nehmen wir an, dass er ein Observable zurückgibt. Ich versuche, einen Unit-Test für ChildService zu schreiben.

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;
    }
}

ServerInteraktionsdienst

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

Der Testfall funktioniert einwandfrei, wenn ich den abhängigen Dienst simuliere. d.h.,

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

Die oben beschriebene Methode wird nicht bevorzugt, da ich am Ende möglicherweise "n" Mock-Klassen für "n" Abhängigkeiten schreiben müsste. Deshalb möchte ich meine Unit-Tests mit spyOn erstellen. Allerdings funktioniert der Testfall nicht und wirft "Fehler: Kein Anbieter für Http!". Während ich verstehe, was der Fehler ist, würde ich gerne wissen, warum er ausgelöst wird, obwohl ich den abhängigen Dienst überwache. Es scheint, dass das "spyOn" nicht funktioniert.

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

Übersehe ich etwas Offensichtliches?

Antwort #1

Der Testfall funktioniert jedoch nicht und wirft "Fehler: Kein Anbieter für Http!".

Weil du den Dienst immer noch in den providers hast, versucht Angular ihn also immer noch zu erstellen

providers: [
 InteractWithServerService,
    ChildService],

Was Sie anstelle der Erstellung einer Schein-Klasse tun können, ist einfach so etwas wie

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

Hier verwendest du useValue, das ein beliebiges Objekt bereitstellt. Dies wird der Wert sein, der beim Injizieren verwendet wird. Im obigen Fall ist es nur ein willkürliches Objekt mit deiner Mock-Methode.

Wenn Sie spionieren möchten, um verschiedene Werte liefern zu können, könnten Sie den InteractWithServerService injizieren und dann Folgendes tun

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

Eine andere Sache, die Sie tun könnten, ist, das Http mit einem Dummy-Objekt zu verspotten

{ provide: Http, useValue: {} }

Jetzt wird der InteractWithServerService funktionieren (einfach die Klasse zu den Providern hinzufügen, wie du es derzeit hast). Und du kannst einfach darauf spionieren

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

Antwort #2

Verwendung von jasmine 2.6.2: get ist eine Funktion, daher müssen Sie der obigen Antwort die Pfeilfunktionsnotation hinzufügen:

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

Verwandte Artikel