typescript - Hvordan mocke en observabel verdi fra en tjeneste i Angular 7?
Jeg har prøvd å skrive enhetstester for Angular-komponenten min. For øyeblikket, i tjenestekallet mitt for å hente data til komponenten min, har jeg et observabelt som får verdien true når kallet er fullført. Dette observablet abonneres på i komponenten min, slik at komponenten vet når kallet er fullført. Jeg har klart å lage en mock av datakallet i komponenten, men jeg sliter med å finne en måte å mocke den enkeltstående observable-verdien på.
Alle spørsmålene på SO som jeg kan finne handler alle om å mocke et funksjonskall fra tjenesten i komponenten, men ingen som jeg kan finne handler om å mocke en enkelt observable.
Her er funksjonskallet mitt i tjenesten. Som du kan se, får observablen en ny verdi når finalize-funksjonen kjører:
public getSmallInfoPanel(key: string): BehaviorSubject<InfoPanelResponse> {
if (key) {
this.infoPanel = new BehaviorSubject<InfoPanelResponse>(null);
this.http.get(`${this.apiUrl}api/Panels/GetInfoPanel/${key}`).pipe(
retry(3),
finalize(() => {
this.hasLoadedSubject.next(true);
}))
.subscribe((x: InfoPanelResponse) => this.infoPanel.next(x));
}
return this.infoPanel;
}
Her er hvordan jeg opprettet Observable i tjenesten:
private hasLoadedSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public hasLoadedObs: Observable<boolean> = this.hasLoadedSubject.asObservable();
Så i min komponent abonnerer jeg på Observable opprettet fra BehaviourSubject:
public hasLoaded: boolean;
ngOnInit() {
this.infoPanelSmallService.hasLoadedObs.subscribe(z => this.hasLoaded = z);
}
Når jeg kjører ng test, feiler komponenttesten fordi den ikke vet hva hasLoadedObs er, så den kan ikke abonnere på det.
Gi meg beskjed hvis jeg kan gi mer informasjon. Takk.
OPPDATERING 1
describe('InformationPanelSmallComponent', () => {
let component: InformationPanelSmallComponent;
let fixture: ComponentFixture<InformationPanelSmallComponent>;
let mockInfoPanelService;
let mockInfoPanel: InfoPanel;
let mockInfoPanelResponse: InfoPanelResponse;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
FontAwesomeModule,
HttpClientTestingModule
],
declarations: [InformationPanelSmallComponent, CmsInfoDirective],
providers: [
{ provide: InfoPanelSmallService, useValue: mockInfoPanelService }
]
})
.compileComponents();
}));
beforeEach(() => {
mockInfoPanel = {
Title: 'some title',
Heading: 'some heading',
Description: 'some description',
ButtonText: 'some button text',
ButtonUrl: 'some button url',
ImageUrl: 'some image url',
Key: 'test-key',
SearchUrl: '',
VideoUrl: ''
}
mockInfoPanelResponse = {
InfoPanel: mockInfoPanel
}
fixture = TestBed.createComponent(InformationPanelSmallComponent);
component = fixture.componentInstance;
mockInfoPanelService = jasmine.createSpyObj(['getSmallInfoPanel']);
component = new InformationPanelSmallComponent(mockInfoPanelService);
component.key = "test-key"
});
it('should create', () => {
expect(component).toBeTruthy();
});
//TO DO
it('should get info panel from info panel service', () => {
mockInfoPanelService.getSmallInfoPanel.and.returnValue(of(mockInfoPanelResponse));
component.ngOnInit();
expect(mockInfoPanelService.getSmallInfoPanel).toHaveBeenCalled();
expect(component.infoPanel).toEqual(mockInfoPanel);
});
});
Svar #1
Jeg fant ut at det hadde å gjøre med rekkefølgen jeg mocket tjenesten og opprettet komponenten. Jeg brukte også TestBed.overrideProvider, som er noe annet enn det jeg brukte ovenfor. Dette er den endelige testfilen:
describe('InformationPanelSmallComponent', () => {
let component: InformationPanelSmallComponent;
let fixture: ComponentFixture<InformationPanelSmallComponent>;
let mockInfoPanelService;
let mockInfoPanel: InfoPanel;
let mockInfoPanelResponse: InfoPanelResponse;
beforeEach(async(() => {
mockInfoPanelService = jasmine.createSpyObj(['getSmallInfoPanel', 'hasLoadedObs']);
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
FontAwesomeModule,
HttpClientTestingModule
],
declarations: [InformationPanelSmallComponent, CmsInfoDirective, UrlRedirectDirective],
providers: [
{ provide: 'BASE_URL', useValue: '/' },
{ provide: 'API_URL', useValue: '/' }
]
})
TestBed.overrideProvider(InfoPanelSmallService, { useValue: mockInfoPanelService });
TestBed.compileComponents();
}));
beforeEach(() => {
mockInfoPanel = {
Title: 'some title',
Heading: 'some heading',
Description: 'some description',
ButtonText: 'some button text',
ButtonUrl: 'some button url',
ImageUrl: 'some image url',
Key: 'test-key',
SearchUrl: '',
VideoUrl: ''
}
mockInfoPanelResponse = {
InfoPanel: mockInfoPanel
}
fixture = TestBed.createComponent(InformationPanelSmallComponent);
component = fixture.componentInstance;
mockInfoPanelService.getSmallInfoPanel.and.returnValue(of(mockInfoPanelResponse));
mockInfoPanelService.hasLoadedObs = of(true);
component.key = "test-key"
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('ngOnInit', () => {
it('should get info panel from info panel service', () => {
expect(component.hasLoaded).toEqual(true);
expect(mockInfoPanelService.getSmallInfoPanel).toHaveBeenCalled();
expect(component.infoPanel).toEqual(mockInfoPanel);
});
it('should get loaded is true from service', () => {
expect(component.hasLoaded).toEqual(true);
});
});
});
Jeg fikk da ingen flere feil, og testene fungerte faktisk korrekt. Takk til @RuiMarques og andre for all hjelp.
