使用订阅功能测试Observable

时间:2018-08-19 16:12:46

标签: angular jasmine rxjs angular5 rxjs6

这是测试平台的设置。模拟并提供所需的一切:

 let component: PageUploadContainer;
  let store;
  let route;
  let fixture: ComponentFixture<PageUploadContainer>;
  const sanitizer = jasmine.createSpyObj('sanitizer', ['bypassSecurityTrustResourceUrl']);
  sanitizer.bypassSecurityTrustResourceUrl.and.callFake(url => url);
  const mockTranslate = {
    instant: label => label,
  };

  beforeEach(() => {
    store = createMockStore<AppState>(reducers);
    route = new MockActivatedRoute();
  });

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [translationModule],
      declarations: [
        PageUploadContainer,
        MockTranslatePipe,
        MockTranslateCutPipe,
      ],
      schemas: [NO_ERRORS_SCHEMA],
      providers: [
        FormBuilder,
        { provide: DomSanitizer, useValue: sanitizer },
        { provide: Store, useValue: store },
        { provide: ActivatedRoute, useValue: route },
        { provide: TranslateService, useFactory: () => mockTranslate },
      ],
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(PageUploadContainer);
    component = fixture.componentInstance;
    component.mappingTriggered$ = Observable.of(false);
  });

我有以下代码,我使用testBed设置了测试:

onGoTo(uploadStep: string) {
    if (uploadStep === NAVIGATION.DEFAULT) {
      this.store.dispatch(new ReplaceSelectedCompanies([]));
      this.companyIds$.filter(isEmpty)
        .take(1)
        .subscribe(() => {
          this.store.dispatch(new Navigate({ direction: uploadStep}));
        });
    } else {
      this.store.dispatch(new Navigate({ direction: uploadStep}));
    }
  }

还有我的测试。由于new Navigate({ direction: uploadStep})由于其异步性质而未被调用,因此该测试失败

it('if navigation default and companyIds empty should call navigate', () => {
       component.companyIds$ = Observable.of(['123', '234']);
      component.onGoTo(NAVIGATION.DEFAULT);
      expect(store.dispatch).toHaveBeenCalledWith(new ReplaceSelectedCompanies([]));
      expect(store.dispatch).toHaveBeenCalledWith(new Navigate({ direction: NAVIGATION.DEFAULT }));
    });

您能帮我测试这些方法吗?

2 个答案:

答案 0 :(得分:0)

您可以在测试代码完全执行后通过调用done()来创建异步Jasmine测试。您可以从测试规范中将done函数作为参数传递,如下所示:

it('if navigation default and companyIds empty should call navigate', (done) => {
   ...
});

但是,当代码完全执行时,您不会在测试代码中知道。我建议从onGoTo返回一个Promise。看起来像这样:

onGoTo(uploadStep: string): Promise<void> {
    if (uploadStep === NAVIGATION.DEFAULT) {
      this.store.dispatch(new ReplaceSelectedCompanies([]));
      return new Promise(resolve => this.companyIds$.filter(isEmpty)
        .take(1)
        .subscribe(() => {
          this.store.dispatch(new Navigate({ direction: uploadStep}));
          resolve();
        }));
    } else {
      this.store.dispatch(new Navigate({ direction: uploadStep}));
      return Promise.resolve();
    }
  }

然后,像这样修改测试代码:

it('if navigation default and companyIds empty should call navigate', (done) => {
   component.companyIds$ = Observable.of(['123', '234']);
  component.onGoTo(NAVIGATION.DEFAULT).then(() => {
    expect(store.dispatch).toHaveBeenCalledWith(new ReplaceSelectedCompanies([]));
    expect(store.dispatch).toHaveBeenCalledWith(new Navigate({ direction: NAVIGATION.DEFAULT }));
    done()});
});

答案 1 :(得分:0)

尽管我不确定,您可能只需要导入angular提供的async方法即可。

常规示例

it("description", async( /* function */ ));

您的代码

import { async } from "@angular/core/testing";

it('if navigation default and companyIds empty should call navigate', async(() => {
  component.companyIds$ = Observable.of(['123', '234']);
  component.onGoTo(NAVIGATION.DEFAULT);
  expect(store.dispatch)
    .toHaveBeenCalledWith(new ReplaceSelectedCompanies([]));
  expect(store.dispatch)
    .toHaveBeenCalledWith(new Navigate({ direction: NAVIGATION.DEFAULT }));
}));

建议

首先,我会watch this video about angular 6 asynchronous unit tests。整个单元测试系列也不错。

您有很多自定义的模拟类,因此我对此不作过多评论。我建议您使用RouterTestingModule.withRoutes({ /* test routes */ })Here's another video in that series that talks about the RouterTestingModule

然后,您总是可以得到模拟路由器,例如router = TestBed.get(Router)RouterTestingModule创建的其他对象。