我正在使用Jasmine编写针对Angular 8应用程序的测试。我已经为确认对话框编写了测试。显示确认对话框时,我需要检查三个条件。重置,拒绝和批准。当我运行npm test cover进行测试覆盖时,突出显示了下面代码的其他部分未覆盖。我认为我的测试(应该称为拒绝确认对话框)应该已经涵盖了它。 我不确定为什么测试没有涵盖所有内容?有人可以帮忙吗
if (type === 'Approve') {
this.confirmationDialog.show(this.approvalMessage, type, () => this.confirm(type));
} else if (type === 'Reset') {
this.confirmationDialog.show(this.resetMessage, type, () => this.confirm(type));
} else if (type === 'Reject') {
this.confirmationDialog.show(this.rejectMessage, type, () => this.confirm(type));
}
组件代码
export class ApproveComponent {
public showMessage = false;
public message: string;
public body = 'Loading content for approval...';
public loading = true;
public permissions: NgxPermissionsObject;
private id: string;
private type: string;
private approvalMessage = 'Are you sure the information is correct and you want to approve?';
private resetMessage = 'Are you sure you want to reset this approval back to the start?';
private rejectMessage = 'Are you sure you want to reject this approval? ' +
'Rejecting an approval is permanent and will close this process and prevent it progressing further.';
constructor(
private router: Router,
private route: ActivatedRoute,
private service: ApprovalsService,
private ngxPermissionsService: NgxPermissionsService,
private messageService: MessageService,
public confirmationDialog: ConfirmationDialogService) {
this.route.params.subscribe(params => {
this.id = params['id'];
this.type = params['type'];
this.loading = true;
this.service.get(this.type, this.id).then(x => {
if (!x) { return; }
this.loading = false;
this.body = x.body;
});
});
this.permissions = this.ngxPermissionsService.getPermissions();
}
public confirmation = (type: 'Reset' | 'Reject' | 'Approve') => {
if (!this.showMessage
&& ((type === 'Approve' && this.permissions.ViewNotes)
|| (type !== 'Approve'))) {
this.showMessage = true;
return;
}
if (!this.message
&& ((type === 'Approve' && this.permissions.ViewNotes)
|| (type !== 'Approve'))) {
this.messageService.add('Message is required.', 'warning');
return;
}
if (type === 'Approve') {
this.confirmationDialog.show(this.approvalMessage, type, () => this.confirm(type));
} else if (type === 'Reset') {
this.confirmationDialog.show(this.resetMessage, type, () => this.confirm(type));
} else if (type === 'Reject') {
this.confirmationDialog.show(this.rejectMessage, type, () => this.confirm(type));
}
}
public confirm = (type: 'Reset' | 'Reject' | 'Approve') => {
let promise;
if (type === 'Reset') {
promise = this.service.reset(this.id, this.type, this.message);
} else if (type === 'Reject') {
promise = this.service.reject(this.id, this.type, this.message);
} else if (type === 'Approve') {
promise = this.service.approve(this.id, this.type, this.message);
}
promise.then(() => {
this.messageService.add(`Successfully ${type}.`, 'info');
this.navigateToApprovalList();
});
}
private navigateToApprovalList = () => this.router.navigate(['/approvals']);
}
测试组件
describe('ApproveComponent', () => {
let component: ApproveComponent;
let injector: TestBed;
let fixture: ComponentFixture<ApproveComponent>;
const mockService: ApprovalsService = <ApprovalsService>{
approve: (id: string, type: string, message: string) => <Promise<any>>{},
reset: (id: string, type: string, message: string) => <Promise<any>>{},
reject: (id: string, type: string, message: string) => <Promise<any>>{},
get: (type: string, id: string) => <Promise<any>>{},
};
const mockRoute = { params: of({ id: '123', type: 'test' }), snapshot: {} };
function setupComponent(getResult: any = {}) {
spyOn(mockService, nameof<ApprovalsService>('approve')).and.returnValue(Promise.resolve({}));
spyOn(mockService, nameof<ApprovalsService>('reset')).and.returnValue(Promise.resolve({}));
spyOn(mockService, nameof<ApprovalsService>('reject')).and.returnValue(Promise.resolve({}));
spyOn(mockService, nameof<ApprovalsService>('get')).and.returnValue(Promise.resolve(getResult));
TestBed.configureTestingModule({
imports: [
DxTextAreaModule,
DxButtonModule,
SharedModule,
RouterTestingModule.withRoutes([{ path: 'approvals', component: ApproveComponent }])
],
declarations: [ApproveComponent],
providers: [
{ provide: ApprovalsService, useValue: mockService },
{ provide: ActivatedRoute, useValue: mockRoute },
{ provide: MessageService, useClass: MockMessageService },
{ provide: ConfirmationDialogService, useValue: ConfirmationDialogServiceMock },
{ provide: NgxPermissionsService, useClass: MockNgxPermissionsService }
]
})
.compileComponents();
fixture = TestBed.createComponent(ApproveComponent);
injector = getTestBed();
component = fixture.componentInstance;
spyOn((<any>component).router, 'navigate').and.returnValue(true);
fixture.detectChanges();
}
it('should create and call get', () => {
setupComponent();
expect(component).toBeTruthy();
expect(mockService.get).toHaveBeenCalled();
});
it('should call get and do not set body on empty result', () => {
setupComponent(null);
expect(component).toBeTruthy();
expect(component.body).toBe('Loading content for approval...');
});
it('should call confirmation dialog when accept confirmation is called', () => {
setupComponent();
const dialogService = injector.get(ConfirmationDialogService);
const dialogServiceSpy = spyOn(dialogService, 'show').and.callThrough();
component.showMessage = true;
component.message = 'Approved because potato';
fixture.ngZone.run(() => component.confirmation('Approve'));
expect(dialogServiceSpy).toHaveBeenCalled();
expect(dialogServiceSpy).toHaveBeenCalled();
});
it('should call reject confirmation dialog', () => {
setupComponent();
const dialogService = injector.get(ConfirmationDialogService);
const dialogServiceSpy = spyOn(dialogService, 'show').and.callThrough();
component.showMessage = true;
component.message = 'rejected because potato';
fixture.ngZone.run(() => component.confirmation('Reject'));
expect(dialogServiceSpy).toHaveBeenCalled();
expect(mockService.reject).toHaveBeenCalled();
});
it('should call reset confirmation dialog', () => {
setupComponent();
const dialogService = injector.get(ConfirmationDialogService);
const dialogServiceSpy = spyOn(dialogService, 'show').and.callThrough();
component.showMessage = true;
component.message = 'rejected because potato';
fixture.ngZone.run(() => component.confirmation('Reset'));
expect(dialogServiceSpy).toHaveBeenCalled();
expect(mockService.reset).toHaveBeenCalled();
});
it('should set showMessage when reject is called', () => {
setupComponent();
component.showMessage = false;
fixture.ngZone.run(() => component.confirmation('Reject'));
expect(component.showMessage).toBe(true);
expect(mockService.reject).not.toHaveBeenCalled();
});
it('should not call service when reject is called and message is empty', () => {
setupComponent();
component.showMessage = true;
component.message = '';
fixture.ngZone.run(() => component.confirmation('Reject'));
expect(mockService.reject).not.toHaveBeenCalled();
});
});
答案 0 :(得分:0)
这是因为每个if
语句都必须有其他情况。这是为了防止程序在if true条件下退出。代码覆盖率告诉您最终的“ else”用例未经测试。您需要添加一个测试,以验证如果提供了无效的类型,对话框不会打开。
it('should call reset confirmation dialog', () => {
setupComponent();
const dialogService = injector.get(ConfirmationDialogService);
const dialogServiceSpy = spyOn(dialogService, 'show').and.callThrough();
component.showMessage = true;
component.message = 'rejected because potato';
fixture.ngZone.run(() => component.confirmation('bad-type' as any));
expect(dialogServiceSpy).not.toHaveBeenCalled();
});