2017-02-21 22 views
9

Mam usługę (ChildService), która zależy od innej usługi (InteractWithServerService). Późniejsza usługa (InteractWithServerService) służy do wywoływania serwera i zwracania obserwowalnego typu "any". Dla uproszczenia przyjmijmy, że zwraca on obserwowalne. Próbuję napisać test jednostkowy dla ChildService.testowanie jednostki spyOn obserwowalna usługa w angular2

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

Przypadek testowy działa dobrze, kiedy drwić usługi zależnej. tj

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

Powyższy sposób nie jest korzystne, jako że może skończyć się na piśmie „n” próbne klas „n” zależności. Dlatego chcę utworzyć moje testy jednostkowe za pomocą spyOn. Jednak przypadek testowy nie działa i generuje "Błąd: brak dostawcy dla Http!". Chociaż rozumiem, co to jest błąd, chciałbym wiedzieć, dlaczego jest on rzucany, mimo że szpieguję usługę zależną. Wygląda na to, że "spyOn" nie działa.

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

Czy brakuje mi czegoś oczywistego?

Odpowiedz

8

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

Ponieważ nadal masz usługę w providers, więc kątowa próbuje go utworzyć jeszcze

providers: [ 
InteractWithServerService, 
    ChildService], 

Co można zrobić, zamiast tworzenia makiety klasa jest po prostu zrobić coś takiego

Oto użytkownik, którego używasz useValue, który dostarcza dowolny obiekt. Będzie to wartość użyta po wstrzyknięciu. W powyższym przypadku jest to tylko dowolny obiekt z twoją próbną metodą.

Jeśli chcesz szpiegować, dzięki czemu można zapewnić różne wartości, można wstrzyknąć InteractWithServerService, a następnie wykonaj

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

Inną rzeczą, jaką można zrobić, to mock http z fikcyjnego obiektu

{ provide: Http, useValue: {} } 

Teraz zadziała InteractWithServerService (wystarczy dodać klasę do dostawców takich jak obecnie). Możesz go po prostu szpiegować:

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

Dzięki @peeskillet. Działa jak marzenie. Jedyne, co dotyczy, to "useValue" i zwracanie arbitralnego obiektu dla każdej metody, którą będziesz wywoływać. Zdecydowanie wygląda na brudny (raczej nie taki czysty). Czy w ten sposób kątowe chce, abyśmy napisali testy? –

+0

"Obiekt arbitralny" tak naprawdę nie różni się od używania fałszywej klasy. Jedyną różnicą jest to, że jeden jest zamknięty w klasie. W końcu są one po prostu dowolnymi obiektami. Twoja klasa nie rozszerza rzeczywistego interfejsu usługi. Co sprawia, że ​​nie jest to arbitralne? Liczy się tylko to, że obiekt ma metodę, która zostanie wywołana. –

+0

Nie sposób twierdzę, że fałszywe klasy są lepsze niż useValue.Chodzi mi o to, że zarówno klasa próbna, jak i rozwiązanie useValue nie wyglądają na czyste w porównaniu ze starym sposobem, po prostu wstrzykując klasy zależne i szpiegując je. –