问题
I am new to testing world and I have just started writing unit tests for an existing Angular 2 code. I have a function confirmDelete
which returns Obserable<boolean>
and internally uses ConfirmationService
of PrimeNG to get user's feedback on a popup.
Definition of the function is given below:
confirmDelete(): Observable<boolean> {
let confirmObservable = Observable.create((observer: Observer<boolean>) => {
this.confirmationService.confirm({
header: 'Delete Confirmation',
message: 'Do you really want to delete this record?',
accept: () => {
observer.next(true);
observer.complete();
},
reject: () => {
observer.next(false);
observer.complete();
}
});
});
return confirmObservable;
}
I want to write a unit test for this piece of code. I planned to write a Stub for the ConfirmationService
but because I am new to unit testing world, I am finding it difficult to set up the things.
My question is what is the correct approach to write a unit test in this particular scenario.
EDIT:-
I tried solution proposed by @peeskillet but then I started getting type mismatch error between ConfirmationService
and MockConfirmationService
.
Below are the declarations of ConfirmationService
and Confirmation
classes found in the PrimeNG library.
export interface Confirmation {
message: string;
icon?: string;
header?: string;
accept?: Function;
reject?: Function;
acceptVisible?: boolean;
rejectVisible?: boolean;
acceptEvent?: EventEmitter<any>;
rejectEvent?: EventEmitter<any>;
}
export declare class ConfirmationService {
private requireConfirmationSource;
private acceptConfirmationSource;
requireConfirmation$: Observable<Confirmation>;
accept: Observable<Confirmation>;
confirm(confirmation: Confirmation): this;
onAccept(): void;
}
回答1:
I would probably make the mock hold on to the references of the accept
and reject
functions. Then in the test you can call them to check that they emit the correct boolean value. Something like
class MockConfirmationService {
accept: Function;
reject: Function;
confirm(config: any) {
this.accept = config.accept;
this.reject = config.reject;
}
}
Then in your test just call the accept
to test that true
is emitted, and call reject
to test that false
is emitted.
describe('serivce: ModalService', () => {
let modalService: ModalService;
let confirmService: MockConfirmationService;
beforeEach(() => {
confirmService = new MockConfirmationService();
TestBed.configureTestingModule({
providers: [
ModalService,
{ provide: ConfirmationService, useValue: confirmService }
]
});
modalService = TestBed.get(ModalService);
});
it('should return true when accepted', async(() => {
modalService.confirmDelete().subscribe(result => {
expect(result).toBe(true);
console.log('accepted test complete');
});
confirmService.accept();
}));
it('should return false when rejected', async(() => {
modalService.confirmDelete().subscribe(result => {
expect(result).toBe(false);
console.log('rejected test complete');
});
confirmService.reject();
}));
});
回答2:
I've built off of peeskillet's answer. The p-confirmDialog component calls the subscribe of the service, so I had to added requireConfirmationSource, which I found in the PrimeNg source. My mock is as follows:
//
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
//
export class ConfirmationServiceMock {
public key: string = 'mock1';
public header: string = 'Delete Confirmation';
public icon: string = '';
public message: string = '';
// Call Accept to emulate a user accepting
public accept: Function;
// Call Reject to emulate a user rejecting
public reject: Function;
private requireConfirmationSource = new Subject<any>();
requireConfirmation$ = this.requireConfirmationSource.asObservable();
//
public confirm(config: any) {
console.log( 'In confirm service mock...' );
this.message = config.message;
this.accept = config.accept;
this.reject = config.reject;
console.log( this.message );
return this;
}
}
//
来源:https://stackoverflow.com/questions/40592637/unit-testing-angular-observables