为 ng-bootstrap modal (NgbModal) 编写单元测试 [Angular 6]

Ami*_*mir 3 unit-testing jasmine karma-jasmine ng-bootstrap angular

我在为我的应用程序中的确认模式编写单元测试时遇到了一些问题。这是我想测试的一段代码:

  confirmModal(prompt = 'Are you sure?', title = 'Confirm'): Observable<boolean> {
    const modal = this.ngbModal.open(
      ConfirmModalComponent, { backdrop: 'static' });

    modal.componentInstance.prompt = prompt;
    modal.componentInstance.title = title;

    return from(modal.result).pipe(
      catchError(error => {
        console.warn(error);
        return of(undefined);
      })
    );
  }
Run Code Online (Sandbox Code Playgroud)

有什么建议或例子吗?

Ian*_*n A 6

我已经根据您的代码片段编写了以下测试类:

import { TestBed, ComponentFixture } from '@angular/core/testing';
import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { ConfirmModalComponent } from './confirm-modal.component';
import { MyComponent } from './test';

// Mock class for NgbModalRef
export class MockNgbModalRef {
    componentInstance = {
        prompt: undefined,
        title: undefined
    };
    result: Promise<any> = new Promise((resolve, reject) => resolve(true));
}

describe('MyComponent tests', () => {

    let fixtureUnderTest: ComponentFixture<MyComponent>;
    let componentUnderTest: MyComponent;
    let ngbModal: NgbModal;
    let mockModalRef: MockNgbModalRef = new MockNgbModalRef();

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [
                MyComponent
            ],
            imports: [
                NgbModule.forRoot()
            ]
        }).compileComponents();

        fixtureUnderTest = TestBed.createComponent(MyComponent);
        componentUnderTest = fixtureUnderTest.componentInstance;
        ngbModal = TestBed.get(NgbModal);
    });

    it('should open modal', () => {
        spyOn(ngbModal, 'open').and.returnValue(mockModalRef);
        componentUnderTest.confirmModal();
        expect(ngbModal.open).toHaveBeenCalledWith(ConfirmModalComponent, { backdrop: 'static' });
    });

    it('should set prompt and title to defaults', () => {
        spyOn(ngbModal, 'open').and.returnValue(mockModalRef);
        componentUnderTest.confirmModal();
        expect(mockModalRef.componentInstance.prompt).toBe('Are you sure?');
        expect(mockModalRef.componentInstance.title).toBe('Confirm');
    });

    it('should return the result of the modal', (done: DoneFn) => {
        spyOn(ngbModal, 'open').and.returnValue(mockModalRef);
        componentUnderTest.confirmModal().subscribe((result: boolean) => {
            expect(result).toBe(true);
            done();
        });
    });

    it('should return undefined if there is an error', (done: DoneFn) => {
        spyOn(ngbModal, 'open').and.returnValue(mockModalRef);
        // Override the result returned from the modal so we can test what happens when the modal is dismissed
        mockModalRef.result = new Promise((resolve, reject) => reject(false));
        componentUnderTest.confirmModal().subscribe((result: boolean) => {
            expect(result).toBeUndefined();
            done();
        });
    });

});

Run Code Online (Sandbox Code Playgroud)

测试如下:

  1. 应该打开模态:测试ngbModal.open使用正确参数调用的方法。

  2. 应该设置prompttitle为默认值:测试prompttitle属性在模式打开后是否正确设置为其默认值。为此,我必须将以下对象添加到 中,MockNgbModalRef以便组件本身可以更新提示和标题的值。

componentInstance = {
    prompt: undefined,
    title: undefined
};
Run Code Online (Sandbox Code Playgroud)
  1. 应该返回模态的结果:测试modal.result从该方法返回的值。使用返回 Observable 的方法,我需要订阅它并在订阅中执行断言。我已经注入,DoneFn以便done()在断言后调用。这意味着如果断言永远不会发生(例如,组件中存在错误),则done()永远不会被调用并且测试将失败。

  2. 如果出现错误,则应返回 undefined:与 #3 类似,但是它会检查是否模态的结果被拒绝(即存在错误),然后返回 undefined。

  • @RafałGąsior 为了快速修复,请尝试将 `spyOn(ngbModal, 'open').and.returnValue(mockModalRef);` 更改为 `spyOn(ngbModal, 'open').and.returnValue(mockModalRef as any);` (4认同)