typescript - HUR TESTA ANGULAR - catchError-operatorn 'rxjs'
kan du snälla hjälpa mig att testa koden. Jag har inte kunnat testa catchError-operatören som finns inuti pipen av observable interval (1000) ...
Jag vet inte mycket om enhetstestning i Angular för observables av ett intervall (1000). Jag behöver simulera körningen av ett intervall och simulera felet. Jag har inte gjort koden, koden var redan gjord, jag är en ny anställd och jag fick uppgiften att göra enhetstestning. Jag vet inte om det är nödvändigt att använda catchError på ett intervall.
Min fil ts är:
import { Injectable, EventEmitter } from '@angular/core';
import {Subscription, Observable, interval, BehaviorSubject, throwError} from 'rxjs';
import {take, map, catchError, finalize} from 'rxjs/operators';
import { environment } from 'environments/environment';
/**
* @Class CounterSessionProvider
* @description This class is a provider for control session time
* @author Andres Giraldo Londoño, Pragma S.A.
*/
@Injectable({
providedIn: 'root',
})
export class CounterSessionProvider {
// 4 minutes
public inactivityTime = 20; // environment.inactivityTime; // environment.inactivityTime -> 20 seconds
counterStateEmitter = new EventEmitter();
currentSubscription: Subscription;
public substracCounter$: BehaviorSubject<boolean>;
constructor() {
this.substracCounter$ = new BehaviorSubject(false);
}
public start() {
this.currentSubscription = this.initInterval().subscribe();
}
public initInterval(): Observable<number> {
return interval(1000).pipe(
take(this.inactivityTime),
map((index: number) => this.inactivityTime - (index + 1)),
catchError(err => {
this.counterStateEmitter.error(err);
return throwError(err);
})
);
}
public restarCounterTime(): void {
this.substracCounter$.next(true);
}
public stop() {
if (this.currentSubscription) {
this.currentSubscription.unsubscribe();
}
this.counterStateEmitter.emit('ABORTED');
}
}
Min fil spec.ts är:
import {fakeAsync, TestBed, tick} from '@angular/core/testing';
import { CounterSessionProvider } from './counter-session.provider';
import {interval, Observable, Subscription, throwError} from 'rxjs';
import {catchError, take} from 'rxjs/operators';
import { TestScheduler } from 'rxjs/testing';
describe('CounterSessionProvider', () => {
let counterSessionProvider: CounterSessionProvider;
let scheduler: TestScheduler;
beforeEach(() => {
counterSessionProvider = new CounterSessionProvider();
});
/*beforeEach(() => {
scheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
});*/
/*it('should throw error when initInterval interval', fakeAsync(() => {
scheduler.run(helpers => {
spyOn(counterSessionProvider, 'initInterval').and.returnValue(throwError('ERROR'));
const actions$ = helpers.hot('--a', { a: 1000 });
const completion$ = helpers.cold('--c', { c: 1000 });
expect(counterSessionProvider.initInterval).toBe(completion$);
});
}));*/
it('should initialize currentSubscription from interval', fakeAsync(() => {
let currentVal = null;
const numberObservable = counterSessionProvider.initInterval();
counterSessionProvider.currentSubscription = numberObservable.subscribe((value: number) => {
currentVal = value;
});
tick(1000);
expect(currentVal).toEqual(19);
counterSessionProvider.currentSubscription.unsubscribe();
}));
it('should emit a String COMPLETE when start() is called', () => {
spyOn(counterSessionProvider, 'start');
counterSessionProvider.start();
counterSessionProvider.counterStateEmitter.subscribe(value => {
expect(value).toEqual('COMPLETE');
});
expect(counterSessionProvider.start).toHaveBeenCalled();
});
it('should call stop()', () => {
spyOn(counterSessionProvider, 'stop');
counterSessionProvider.currentSubscription = new Subscription();
counterSessionProvider.stop();
counterSessionProvider.counterStateEmitter.subscribe((value: string) => {
expect(value).toEqual('ABORTED');
});
expect(counterSessionProvider.stop).toHaveBeenCalled();
});
it('should call method start and initilize currentSubscription', fakeAsync(() => {
counterSessionProvider.start();
tick(1000);
counterSessionProvider.currentSubscription.unsubscribe();
expect(counterSessionProvider.currentSubscription).not.toBeNull();
}));
it('should call restarCounterTime() and emit a TRUE', () => {
counterSessionProvider.restarCounterTime();
counterSessionProvider.substracCounter$.subscribe(value => expect(value).toBeTruthy());
});
it('should call method stop and emit ABORTED', fakeAsync(() => {
counterSessionProvider.start();
tick(1000);
counterSessionProvider.stop();
}));
/*beforeEach(() => {
counterSessionProvider = TestBed.get(CounterSessionProvider);
});
it('should be created', () => {
expect(counterSessionProvider).toBeTruthy();
});
it('should return ABORTED when stop function is called', () => {
counterSessionProvider.start();
counterSessionProvider.counterState.subscribe((msg: string) => {
expect(msg).toEqual('ABORTED');
});
counterSessionProvider.stop();
});*/
});
Men jag behöver täcka hela koden i ditt täckningsområde. I bilden nedan visar jag det täckningsområde som jag behöver.
Försöker att tillämpa de förslag som Shashank Vivek gav mig, det ger dessa resultat:
Svar #1
Det här är vad jag kommer att föreslå, throw något för catchError, något som detta demo annars kommer inte catchError att kallas. Jag är inte säker på om catchError bör tas bort, du bör verifiera det med teamet (eftersom det verkar ha viss kod inuti det)
component.ts
public initInterval(): Observable<number> {
return interval(1000).pipe(
take(this.inactivityTime),
map((index: number) => {
// write some condition to "throw" otherwise "catchError" is of now use
if (this.inactivityTime > 30) {
throw new Error('inactivityTime greater than 30');
}
return this.inactivityTime - (index + 1);
}),
catchError((err) => {
this.counterStateEmitter.error(err);
return throwError(err);
}),
finalize(() => {
this.currentSubscription.unsubscribe();
this.counterStateEmitter.emit('COMPLETE');
})
);
}
och sedan spec.ts sätter du villkoret för att utlösa fel :
it('should handle error in initInterval', fakeAsync(() => {
let currentVal;
let someError;
spyOn(
counterSessionProvider.counterStateEmitter,
'error'
).and.callThrough();
counterSessionProvider.inactivityTime = 35; // just to simulate the error event as per the code I have added
const numberObservable = counterSessionProvider.initInterval();
counterSessionProvider.currentSubscription = numberObservable.subscribe(
(value: number) => {
currentVal = value;
},
(err) => {
someError = err;
}
);
tick(1000);
expect(currentVal).toBeUndefined();
expect(someError).toBeDefined(); // you can also use .toBe('inactivityTime greater than 30')
expect(counterSessionProvider.counterStateEmitter.error).toHaveBeenCalled();
counterSessionProvider.currentSubscription.unsubscribe();
}));
Ge det ett försök och låt mig veta om detta fungerar.
Skärmdump av täckning:


