【问题标题】:Testing Observable with subscribe in a function在函数中使用 subscribe 测试 Observable
【发布时间】:2019-01-25 22:08:58
【问题描述】:

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

 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 }));
    });

你能帮我测试一下这些方法吗?

【问题讨论】:

  • 请发布您的设置。我没有看到测试台。此外,它是异步的,但您的测试是同步运行的。
  • @christo8989 添加了设置

标签: angular jasmine rxjs angular5 rxjs6


【解决方案1】:

虽然我不确定,但您可能只需要导入 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 创建的其他对象。

【讨论】:

    【解决方案2】:

    在您的测试代码完全执行后,您可以通过调用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()});
    });
    

    【讨论】:

      猜你喜欢
      • 2020-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-31
      • 2018-08-06
      • 2020-08-13
      • 2017-06-28
      相关资源
      最近更新 更多